Back to How-Tos

Communicate with an HTTP(S) API from Worfklow

This how-to is meant to show an example of how to communicate with an external service from a Run Script action task in the Automation module (Workflow). It is geared towards users with an existing background in scripting and network communications, as the concepts here are relatively complex for beginners.

WinHttp.WinHttpRequest.5.1

In order to communicate with an exterior server, we will need to use the WinHttp.WinHttpRequest.5.1 object, which you can essentially consider to be somewhat like a web browser. The object can make requests to any HTTP(s) server either by GET or POST, receive the response, and process it using your usual scripting tools.

The basics of establishing an HTTP request with this object is pretty simple (JS):

var http = new ActiveXObject("WinHttp.WinHttpRequest.5.1");
http.open('GET', 'http://example.com/', false);
http.send();
response = http.responseText;
Watch.Log(response, 2);

This is pretty identical to simply opening your browser to the http://example.com/ website, however in this case we're not doing anything with the response - aka we're not displaying it - but it is available to us.

But what is that response? Well in this case it's HTML, but in reality it can be any file or file type, text or binary, that you can grab from the internet. For example, you could grab an image like this Google logo:

var http = new ActiveXObject("WinHttp.WinHttpRequest.5.1");
http.open('GET', 'https://www.google.ca/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png', false);
http.send();
response = http.responseText;
// some code to save the image or use it.

POST data

The other thing you can do is to actually post some data to a server, as if you were submitting a form. This can be useful for many things of course, one example being filling a form online, or communicating with a REST API somewhere on the internet - which is of course what the goal of this how-to is.

Before sending the data though it has to be prepared. Not to go into too many details, but all data going through a POST action must be "formatted" in certain ways to be compatible. Fret not, it's actually fairly simple!

//Set the Post Data string - as a bonus, how to create a string on multiple lines :)
var simplePostData = "param1=Param"+
    "&username=blabla"+
    "&text="+encodeURIComponent("This is text that needs to be url-encoded to be supported properly!");
var http = new ActiveXObject("WinHttp.WinHttpRequest.5.1");
// HTTP needs to be sent to post. The URL is just an example of the receiving form or process
http.open("POST", "http://example.com/formreceive.php", false);
// The Request Header needs to be sent as form data, as shown here
http.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
http.send(simplePostData);

var response = http.responseText;

Ok so... what about posting a file? That's a little more difficult and beyond the scope of this how-to but it is possible. You can start with Sending and Receiving Binary Data to give you an idea (this does require some knowledge of JavaScript to understand, however).

Catching Errors

It's always good practice to attempt to catch errors in your code, so as to react to these errors instead of the Run Script action simply failing in Workflow. In JavaScript, the try {} catch {} commands can be used for this:

try { 
    var http = new ActiveXObject("WinHttp.WinHttpRequest.5.1");
    http.open('GET', 'http://example.com/', false);
    http.send();

} 
catch ( error ) {
    Watch.Log("An error was triggered: '" + (objError.number & 0xFFFF).toString() + "' with description: '" + objError.description +"'",1);
}
var response = http.responseText;
Watch.Log(response, 2);

A complete example

Thankfully, some generous souls have provided the interwebs with plenty of sample REST APIs that we can play with. So, let's try out JSONPlaceholder, which is hosted online (and if you so desire, you can actually use it yourself if you know node and some good javascript!). The following code sample should work for you as-is and will print, in your Workflow Logs, some information for each entry in the /user/ endpoint (it's only 10, don't worry!).

try {
    var http = new ActiveXObject("WinHttp.WinHttpRequest.5.1");
    http.open('GET', 'http://jsonplaceholder.typicode.com/users', false);
    http.send();
}
catch ( error ) {
    Watch.Log("An error was triggered: '" + (objError.number & 0xFFFF).toString() + "' with description: '" + objError.description +"'",1);
}

// Here we convert the response (Which is JSON) into a native JavaScript object:
var response = JSON.parse(http.responseText);

// We can loop through the Object using for...in, so much cleaner than
for(var user in response) {
  Watch.Log("Full Name: " + response[user].name + " lives in " + response[user].address.city, 2);
};

And lastly, an example of posting to that same API, which adds in this case a "blog post" of sorts:

try {
    var http = new ActiveXObject("WinHttp.WinHttpRequest.5.1");
    http.open('POST', 'http://jsonplaceholder.typicode.com/posts', false);
    http.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
}
catch ( error ) {
    Watch.Log("An error was triggered: '" + (objError.number & 0xFFFF).toString() + "' with description: '" + objError.description +"'",1);
}

var postData = "title="+encodeURIComponent("Blog Post Title")+"&"
               +"body="+encodeURIComponent("A possibly multi-line blogpost\nWith text and some characters and $#%^.")+"&"
               +"userId=9";

http.send(postData);

// The response we get here is also a JSON object, which we can read directly:
var response = JSON.parse(http.responseText);

// In the response we have the "id" field which is where that blog post is located:
var postID = response.id;

// And now we post the ID of this new post. Normally this would be dynamic ;)
Watch.Log("Post ID: "+postID, 2);