Sanity Check code

According to the documentation that should be “SendSync”

https://documentation.xojo.com/api/networking/urlconnection.html#urlconnection-send
https://documentation.xojo.com/api/networking/urlconnection.html#urlconnection-sendsync

Only the SendSync method returns a string.

2 Likes

Change Send to SendSync.

Hi Chris, try not to get too overwhelmed - it takes a while sometimes before the “ah-hah!” moment where all this programming stuff clicks and the lightbulb over your head appears. I think @Ian_Kennedy is offering you some good advice, and I can certainly chip in.

To begin with I like to build apps (like yours) one piece at a time, test it, save it, and then add another layer - debugging as I go.

Your app is a rather complex one for someone claiming to be new to programming, but the XOJO platform will help you make quick work of it.

The example projects that shipped with your copy of XOJO do have two good examples of the POST and GET methods of a URLConnection. This URLConnection is really the heart of the app you’re working on.

The part that I have gotten tripped up on before is the concept of an asynchronous request, where the response is somewhat detached and not (visibly) tied to the sequential execution of your code. A bit like tossing a message over a wall, then a short period later it’s tossed back. When it arrives your app is anticipating it, but for me it was hard to understand where and when it would land.

Getting back to the basics of your Autotask API and building the pieces that send and later receive your transaction…

You need to create a variable to store your URLConnection object, where it will persist beyond the scope of the method calling it. For the sake of this discussion I’m assuming you are making a Desktop application (not a multi-user WebApp, which has more rules to consider).

Create a Var in the App object, declare it as a URLConnection, and create a New instance of it each time you use it.

E.g., “App.my_Autotask_API = New URLConnection

Again, back to the App object, create a method with a name something like “my_Autotask_API_ContentReceived_action”, that takes a number of parameters:

Sender As URLConnection, URL As String, HTTPStatus As Integer, content As String

…all the same parameters as you see defined in the documentation.

In the method you’re writing declare some AddHandler’s that ‘watch’ for the URLConnection’s ContentReceived() event, something like this…

AddHandler my_Autotask_API.ContentReceived, AddressOf my_Autotask_API_ContentReceived_action

Now create a really dumbed-down call (some code in a simple button will work) where you create the “GET” request using ''App.my_Autotask_API", and then see what comes back to you in the my_Autotask_API_ContentReceived_action. I hope this helps!

2 Likes

I do, sorry. Too many languages right now.

1 Like

Thanks I am going to try and rewrite it again. I have the code done which writes entries via the API so I know it works. Just got to get it the other way around but that’s what I am struggling with

The code above needs to be re-ordered.

// Autotask API URL to retrieve list of companies
Var url As String = apiEndpoint + "/Companies/query?search={""filter"":[{""op"":""eq"",""field"":""CompanyType"",""value"":""1""}]}"


// Set HTTP Request 
URLConnection1.SetRequestContent("Content-type", "application/json")
URLConnection1.RequestHeader("ApiIntegrationCode", integrationCode)
URLConnection1.RequestHeader("UserName", apiUsername)
URLConnection1.RequestHeader("Secret", apiPassword)

// Get Response
Var response As String = URLConnection1.SendSync("GET", url, 30)


// Parse JSON response
Var json As New JSONItem(response)

[...]
1 Like

Thanks @Jeremie_L I have reordered it but does not work. Its telling me that there is

Window1.Button1.Pressed, line 15
There is more than one method with this name but this does not match any of the available signatures.
URLConnection1.RequestHeader("ApiIntegrationCode", integrationCode)
/API credentials
Var  apiUsername As String = Username”
Var  apiPassword As String = “Password”
Var  integrationCode As String = “code”
Var apiEndpoint As String = "https://webservices16.autotask.net/atservicesrest/V1.0"


// Autotask API URL to retrieve list of companies
Var url As String = apiEndpoint + "/Companies/query?search={""filter"":[{""op"":""eq"",""field"":""CompanyType"",""value"":""1""}]}"



// Set HTTP Request 
URLConnection1.SetRequestContent("Content-type", "application/json")
URLConnection1.RequestHeader("ApiIntegrationCode", integrationCode)
URLConnection1.RequestHeader("UserName", apiUsername)
URLConnection1.RequestHeader("Secret", apiPassword)

// Get Response
Var response As String = URLConnection1.SendSync("GET", url, 30)


// Parse JSON response
Var json As New JSONItem(response)

// Extract company data from JSON response
Var companies() As Dictionary
For Each account As JSONItem In json.Value("items")
  Var company As New Dictionary
  company.Value("id") = account.Value("id").ToInteger
  company.Value("name") = account.Value("companyName").ToString
  company.Value("phone") = account.Value("phone").ToString
  company.Value("website") = account.Value("webAddress").ToString
  company.Value("city") = account.Value("city").ToString
  company.Value("state") = account.Value("state").ToString
  company.Value("country") = account.Value("countryID").ToString
  companies.Add(company)
  
Next

// Display company data
For Each company As Dictionary In companies
  ListBox1.AddRow("ID: " + company.Value("id").ToString)
  ListBox1.AddRow("Name: " + company.Value("name").ToString)
  ListBox1.AddRow("Phone: " + company.Value("phone").ToString)
  ListBox1.AddRow("Website: " + company.Value("website").ToString)
  ListBox1.AddRow("City: " + company.Value("city").ToString)
  ListBox1.AddRow("State: " + company.Value("state").ToString)
  ListBox1.AddRowt("Country: " + company.Value("country").ToString)
Next```




I am trying to base it on this code below, which writes a company via the API and works well, Now all I want to do is get the companies and put into alist

THIS CODE BELOW WORKS WELL

//API credentials

Var apiUsername As String = Username”

Var apiPassword As String = “Password”

Var integrationCode As String = “code”

Var apiEndpoint As String = "https://webservices16.autotask.net/atservicesrest/V1.0"

//Make a Json item with all the infomation.

Var requestBody as New JSONItem

requestBody.Value("companyType") = custType

requestBody.Value("ownerResourceID") = 29682885

requestBody.Value("companyName") =CompanyText.text

requestBody.Value("Address1") = Address1Text.Text

requestBody.Value("Address2") =Address2Text.Text

requestBody.Value("City") = CityText.Text

requestBody.Value("State") = StateText.Text

requestBody.Value("postalcode") = ZipCodeText.Text

//requestBody.Value("CountryID") = CountryIDText.Text

requestBody.Value("Phone") = phoneText.Text

requestBody.Value("WebAddress") =webText.Text

requestBody.Value("Country") = CountyCombo.Text

//Write the values back to Autotask using the Information foiund in the JSON Item

URLConnection1.SetRequestContent(requestBody.ToString, "application/json")

URLConnection1.RequestHeader("ApiIntegrationCode") = integrationCode

URLConnection1.RequestHeader("UserName") = apiUsername

URLConnection1.RequestHeader("Secret") = apiPassword

//This is what does the actual Send

URLConnection1.send("POST",apiEndpoint)

Arg, sorry I copy-pasted your code without actually verifying the syntax.

This might work better:

//API credentials
Var  apiUsername As String = "Username"
Var  apiPassword As String = "Password"
Var  integrationCode As String = "code"
Var apiEndpoint As String = "https://webservices16.autotask.net/atservicesrest/V1.0"


// Autotask API URL to retrieve list of companies
Var url As String = apiEndpoint + "/Companies/query?search={""filter"":[{""op"":""eq"",""field"":""CompanyType"",""value"":""1""}]}"



// Set HTTP Request 
URLConnection1.SetRequestContent("Content-type", "application/json")
URLConnection1.RequestHeader("ApiIntegrationCode") = integrationCode
URLConnection1.RequestHeader("UserName") = apiUsername
URLConnection1.RequestHeader("Secret") = apiPassword

// Get Response
Var response As String = URLConnection1.SendSync("GET", url, 30)


// Parse JSON response
Var json As New JSONItem(response)

// Extract company data from JSON response
Var companies() As Dictionary
Dim itemsArray() as Variant = json.Value("items")
For Each account As JSONItem In itemsArray
  Var company As New Dictionary
  company.Value("id") = account.Value("id").IntegerValue
  company.Value("name") = account.Value("companyName").StringValue
  company.Value("phone") = account.Value("phone").StringValue
  company.Value("website") = account.Value("webAddress").StringValue
  company.Value("city") = account.Value("city").StringValue
  company.Value("state") = account.Value("state").StringValue
  company.Value("country") = account.Value("countryID").StringValue
  companies.Add(company)
  
Next

// Display company data
For Each company As Dictionary In companies
  ListBox1.AddRow("ID: " + company.Value("id").StringValue)
  ListBox1.AddRow("Name: " + company.Value("name").StringValue)
  ListBox1.AddRow("Phone: " + company.Value("phone").StringValue)
  ListBox1.AddRow("Website: " + company.Value("website").StringValue)
  ListBox1.AddRow("City: " + company.Value("city").StringValue)
  ListBox1.AddRow("State: " + company.Value("state").StringValue)
  ListBox1.AddRowt("Country: " + company.Value("country").StringValue)
Next

@Jeremie_L Thanks so much for this. It’s working (or at least not erroring out) but noting is being displayed in the list box.)

When I run it in Postman using this endpoint it returns the companies ok So I know the creds are correct

https://webservices16.autotask.net/atservicesrest/v1.0/Companies/query?search={ "filter":[{"op":"eq","field":"CompanyType","value":1}]}

Is the endpoint set up correctly in XOJO code

Var apiEndpoint As String = "https://webservices16.autotask.net/atservicesrest/V1.0"


// Autotask API URL to retrieve list of companies
Var url As String = apiEndpoint + "/Companies/query?search={""filter"":[{""op"":""eq"",""field"":""CompanyType"",""value"":""1""}]}"

This is the line it stops on
CleanShot 2023-05-17 at 15.55.52[quote=“Jeremie_L, post:28, topic:75764, full:true, username:Jeremie_L”]
Arg, sorry I copy-pasted your code without actually verifying the syntax.

This might work better:

//API credentials
Var  apiUsername As String = "Username"
Var  apiPassword As String = "Password"
Var  integrationCode As String = "code"
Var apiEndpoint As String = "https://webservices16.autotask.net/atservicesrest/V1.0"


// Autotask API URL to retrieve list of companies
Var url As String = apiEndpoint + "/Companies/query?search={""filter"":[{""op"":""eq"",""field"":""CompanyType"",""value"":""1""}]}"



// Set HTTP Request 
URLConnection1.SetRequestContent("Content-type", "application/json")
URLConnection1.RequestHeader("ApiIntegrationCode") = integrationCode
URLConnection1.RequestHeader("UserName") = apiUsername
URLConnection1.RequestHeader("Secret") = apiPassword

// Get Response
Var response As String = URLConnection1.SendSync("GET", url, 30)


// Parse JSON response
Var json As New JSONItem(response)

// Extract company data from JSON response
Var companies() As Dictionary
Dim itemsArray() as Variant = json.Value("items")
For Each account As JSONItem In itemsArray
  Var company As New Dictionary
  company.Value("id") = account.Value("id").IntegerValue
  company.Value("name") = account.Value("companyName").StringValue
  company.Value("phone") = account.Value("phone").StringValue
  company.Value("website") = account.Value("webAddress").StringValue
  company.Value("city") = account.Value("city").StringValue
  company.Value("state") = account.Value("state").StringValue
  company.Value("country") = account.Value("countryID").StringValue
  companies.Add(company)
  
Next

// Display company data
For Each company As Dictionary In companies
  ListBox1.AddRow("ID: " + company.Value("id").StringValue)
  ListBox1.AddRow("Name: " + company.Value("name").StringValue)
  ListBox1.AddRow("Phone: " + company.Value("phone").StringValue)
  ListBox1.AddRow("Website: " + company.Value("website").StringValue)
  ListBox1.AddRow("City: " + company.Value("city").StringValue)
  ListBox1.AddRow("State: " + company.Value("state").StringValue)
  ListBox1.AddRowt("Country: " + company.Value("country").StringValue)
Next

[/quote]

some more on this. WHen I look at JSONException that is generated it gives me this error

ItemsArray Nil
Jason Nil

ItemsArray Nil
Jason Nil

Can’t be what the JSONException says. Nil items raise NilObjectException.

Now, moments ago before you edited, there was something about an unexpected character in the JSON. That certainly is a JSONException, and that we can work with.

The most important question is, what JSON is causing that exception? JSON you wrote, or JSON from the remote API? If the remote API is giving bad JSON, there’s not much you can do about it except contact the API provider.

If it’s from the API, also check that the API didn’t reject your request and return a non-JSON “access denied” type message. The code goes straight from getting the response to turning it into an object, without sanity checking anything.

So If I change my code to use this (which only pulls one company with the id of zero) then ut gives the lexical error

Var apiEndpoint As String = "https://webservices16.autotask.net/atservicesrest/V1.0Companies/0"


// Autotask API URL to retrieve list of companies
//Var url As String = apiEndpoint + "/Companies/query?search={""filter"":[{""op"":""eq"",""field"":""CompanyType"",""value"":""1""}]}"

var url as string = apiEndpoint

Then it generates the following error in JSONExeption.

lexical error: invalid char in json text.

However if I run that same endpoint in post man it returns the company wit the id of 0 correctly

When I change it back to the original one , that’s when I get the error of Nil

Var apiEndpoint As String = "https://webservices16.autotask.net/atservicesrest/V1.0Companies/0"


// Autotask API URL to retrieve list of companies
Var url As String = apiEndpoint + "/Companies/query?search={""filter"":[{""op"":""eq"",""field"":""CompanyType"",""value"":""1""}]}"




Could be what I created because I know that the application is returning information back

Do you have a project to show? Your screenshots are helpful, but don’t provide enough context to find the answers.

The more I look, the weirder things get, and my ability to help you accurately is just failing. Each answer is wildly different from the last, and it changes every time I find a new :man_facepalming: in the code.

How would you like to me show the project. it has the credentials in it, so to run it and get the right information you will need to see it with creds. Should I email to you directly (i have your email) and then I can always change the password later

Yup just send it by email and change your API key once we’re done! :slight_smile:

3 Likes

email sent

Thank you so much for providing me with an example of how this can be done, its completely different to what I had. Will give me some new stuff to learn

1 Like