OK, so finally Wunderlist released a Public API. You can read about the API here: https://developer.wunderlist.com/documentation. The API like all the other APIs use the oAuth 2.0, but Wunderlist isn’t exactly 2.0. It is a partial implementation of oAuth 2.0.
If you scan Github for any libraries for Wunderlist, you will not really find any that refer to the new API ( there are a couple, but they use unofficial APIs), So I thought I could write one because I had a brand new Pebble time AND I was at Bozeman, chilling out and tubing and a lot of time to spend.
The reason why I chose ServiceNow is because I was speaking to one of the Integration Architects and he was asking me what my gotchas are about the new Scoped Application API. I never gave the API a spin, so this looked like an excellent use case to test the Scoped Application API. There is a lot of stuff that I learnt by writing this API, but there is really a lot to do in the app because of the limitations of the Scoped Application API.
So here is what the flow would look like, we only go through some snippets of code to the final product but not the final code in itself.
Below the Highlevel Architectural flow and the components I use to mimic oAuth. When I first saw that ServiceNow supports oAuth, I was excited that I can authenticate other systems using oAuth, then I understood that ServiceNow supports oAuth for authenticating other systems to pull the data, and ServiceNow doesn’t itself provide an API to communicate with other systems, so I had to write an entire landing UI page and a combination of a processor to do so.
High level steps:
code
to the Application invoking it.code
with you, you will have to exchange code
for AccessToken
and store the AccessToken
in a table and linked to a user, so that we don’t have to do all the above steps when ever we try to fetch the tasks/lists for the user.A more technical look at what is happening here:
code
to an endpoint hat you specify in the above step. For this, I used a Processor, which will take any request that it gets and invokes a Script Include to parse the request and get the code
.code
to Access Token.Let’s knock couple of things off before we continue:
g_request
and g_response
objects and even a documentation page. documentation page.
_makeRequestFromRestMessage:function(code){
var code = code+'';
var client_id = gs.getProperty("x_4591_wunderlist.wu_client_id");
var client_secret = gs.getProperty("x_4591_wunderlist.wu_client_secret");
try{
var r = new sn_ws.RESTMessageV2('wu_accessToken', 'post');
r.setStringParameter("client_id", client_id);
r.setStringParameter("code", code);
r.setStringParameter("client_secret", client_secret);
r.setHttpTimeout(10000) //In milliseconds. Wait at most 10 seconds for response from http request.
response = r.execute();
responseBody = response.haveError() ? response.getErrorMessage() : response.getBody();
status = response.getStatusCode();
this._output(responseBody, status);
return responseBody;
}catch(e){
gs.info("error in the API call");
}
},
_makeRequestDirect:function(code){
var code = code+'';
var client_id = gs.getProperty("x_4591_wunderlist.wu_client_id");
var client_secret = gs.getProperty("x_4591_wunderlist.wu_client_secret");
var body = {"client_id":client_id,"client_secret":client_secret,"code":code};
body = new global.JSON().encode(body);
try{
var restMessage = new sn_ws.RESTMessageV2();
restMessage.setHttpMethod("post");
restMessage.setRequestHeader("Content-Type", "application/json");
restMessage.setEndpoint("https://www.wunderlist.com/oauth/access_token");
restMessage.setRequestBody(body);
global.JSUtil.logObject(restMessage.getRequestHeaders(), "The headers");
global.JSUtil.logObject(restMessage.getRequestBody(), "the body");
var response = restMessage.execute();
responseBody = response.haveError() ? response.getErrorMessage() : response.getBody();
status = response.getStatusCode();
this._output("`call is successful - `"+responseBody, status);
return responseBody;
}catch(e){
gs.info("error in the API call");
}
},
global.JSUtil.logObject
and remember when you do so, this would get logged into “Global” log table because you are using a global object.application.<scriptinclude>
. You SHOULD have the Script Include defined in the global
scope for you to even access it from a UI Page.g_request
. If you are using g_request
in a Application Scope, then you don’t have access to any of the functions except the ones here : link. That means you dont have access to any of the inputStreams or Response Body and that means you cannot write your application if you want to handle a post
. and that’s why my Application is incomplete. ServiceNow didn’t provide me with a way to access the request body yet for Scoped application, so if you want to access the body you will STILL have to write your applications in Global Scope.More to come on this.
A sneak peak of my half baked API: https://thawing-fjord-6173.herokuapp.com/ [ built using a simple Node JS Server which access my API on ServiceNow ]
Code and Coffee are better in Mountains.