cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

Making REST calls using Golang to ThingWorx Server

Tanzanite

Making REST calls using Golang to ThingWorx Server

Prerequisite

  • Install Go
  • Install VSCode or desired IDE to write Go code, e.g. GoLand (commercial license required, 30days trial)
  • Install Go extension for VSCode (if you are working with VSCode)

 

Content

  • Building GET Request
  • Building PUT Request
  • Building POST Request

 

Building GET Request

I'll be using net/http package from Go to perform the GET request to the ThingWorx Server by importing it

 

import (
    "net/http"
)

Next, we use the NewRequest() which takes method, URL & body. Since I'm sending a GET request my method will be GET, and the URL to the ThingWorx server & no body so will leave it to nil

 

 

url := myurl
req, _ := http.NewRequest("GET", url, nil)

 

We are ignoring the error that NewRequest is returning as its already handled within the NewRequest() for us

Use Header to add the request header to be received by the ThingWorx Server, note Header is of type map[string] []string (a key : value pair)

 

 

req.Header.Add("appKey", appkey) // passing the appkey from ThingWorx Server for authentication
req.Header.Add("Accept", "application/json") // accepts json as response
req.Header.Add("Cache-Control", "no-cache") // not using cache to fetch data

Now we invoke the DefaultClient to perform the request & handling the error

res, err := http.DefaultClient.Do(req)
    if err != nil {
        log.Println("Failed to get all entity list from the server", err)
    }

We need to close the body once we have received it and then we try to read the Body returned in our request

 

 

defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)

Here's complete function accepting URL & Application Key as string. Notice I am starting the function name with capital which denotes that I am making this as an exported function. See Exported/Unexported Identifiers In Go for more

 

 

func GetTwxServerEntities(myurl string, appkey string) {
    url := myurl
    req, _ := http.NewRequest("GET", url, nil)
    req.Header.Add("appKey", appkey)
    req.Header.Add("Accept", "application/json")
    req.Header.Add("Cache-Control", "no-cache")
    res, err := http.DefaultClient.Do(req)
    if err != nil {
        log.Println("Failed to get all entity list from the server", err)
    }
    defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)
    //fmt.Println(res)
    fmt.Println(string(body))
}

 

Building PUT Request

 

To send property updates to the ThingWorx Server I'll create NewReader to read the strings which is JSON in this example

payload := strings.NewReader("{\"Prop1\" : \"Demo 101\",\"Prop2\" : 1001}")

Like GET request NewRequest is invoked to perform the PUT request like so

 

req, _ := http.NewRequest("PUT", url, payload)

Adding the header details :

req.Header.Add("appKey", appkey)
req.Header.Add("Content-Type", "application/json")
req.Header.Add("Cache-Control", "no-cache")

Invoke the client to perform the request

res, err := http.DefaultClient.Do(req)
if err != nil {
        log.Println("Failed to Put the value to the ThingWorx server", err)
    }

Here's the complete function which takes a URL and appKey and then updates 2 property values for a Thing on the ThingWorx Server:

 

e.g. myurl= http://tw831psql:8080/Thingworx/Things/RESTThing/Properties/*

 

func TwxPut(myurl string, appkey string) {

    url := myurl

    payload := strings.NewReader("{\"Prop1\" : \"Demo 101\",\"Prop2\" : 1001}")

    req, _ := http.NewRequest("PUT", url, payload)

    req.Header.Add("appKey", appkey)
    req.Header.Add("Content-Type", "application/json")
    req.Header.Add("Cache-Control", "no-cache")
    res, err := http.DefaultClient.Do(req)

    if err != nil {
        log.Println("Failed to Put the value to the ThingWorx server", err)
    }
    fmt.Println(res)
    
}

And I can now verify that the property has been updated for the Thing called RESTThing

RouteCreatedScreenshot.png

 

Building POST Request

 

Similar to GET & PUT we have to create new Request of method POST to invoke a Service in this example, for this I have already created a service that counts up a numeric property value stored in the CountUpProp property already existing under the RESTThing entity

 

req, _ := http.NewRequest("POST", url, nil)

Adding the Headers to the req

req.Header.Add("appKey", appKey)
req.Header.Add("Content-Type", "application/json")
req.Header.Add("Cache-Control", "no-cache")

Handling response and the error in case of an issue

res, err := http.DefaultClient.Do(req)
    if err != nil {
        log.Println("Posting to Thingworx server failed with error", err)
    }
    fmt.Println(res)

Here's complete thought :

func TwxPost(myurl string, appKey string) {
    // e.g. http://tw831psql:8080/Thingworx/Things/RESTThing/Services/CountUpService

    url := myurl

    req, _ := http.NewRequest("POST", url, nil)

    req.Header.Add("appKey", appKey)
    req.Header.Add("Content-Type", "application/json")
    req.Header.Add("Cache-Control", "no-cache")

    res, err := http.DefaultClient.Do(req)

    if err != nil {
        log.Println("Posting to Thingworx server failed with error", err)
    }

    fmt.Println(res)

}

Verifying property update after the service invoke

RouteCreatedScreenshot.png

 

All the above functions now can be called for e.g. in a main()

 

func main() {
    var myurl string
    var appkey string
    // Provide URL for ThingWorx
    fmt.Println("Enter URL, eg. http://localhost:8080/Thingworx/Server")
    // accepting URL at runtime
    fmt.Scanln(&myurl)

    // Provide appKey from the ThingWorx platform
    fmt.Println("Enter valid ThingWorx Application Key ")
    // accepting appKey at runtime
    fmt.Scanln(&appkey)

    GetTwxServerEntities(myurl, appkey)
    TwxPut(myurl, appkey)
    TwxPost(myurl, appkey)
}