Getting the IBM Connections API to play nice with Postman/ Chrome

postmanI was doing some work with an Angular application talking to the IBM Connections API. More specifically: I wanted to show and create activities based on some user input.

The Connections API is pretty complex, so I normally run some ‘manual’ tests first based on the documentation, and then use those result to write the code to call the API. My preferred application for that is Postman.

While running the tests in Postman I ran into a big issue. All GET and PUT requests came through fine, but I wasn’t able to create anything using a POST request to the API: every request I made returned a 403 error:

<error xmlns="http://www.ibm.com/xmlns/prod/sn">
<code>403</code>
<message>You are not authorized to perform the requested action.</message>
<trace></trace>
</error>

The funny thing was that using the same credentials, I could create items using the web interface just fine. My first thought was that it must be some strange access control setting hidden away deep in a config file (“don’t allow users to create stuff using the API”), but then I found someone with a similar issue on StackOverflow. And I found this IBM Technote. So, apparently there’s something fishy going on with Postman.

So by enabling the Chrome Developer tools for Postman, I was able to look at the exact HTTP request that Postman sends. And I found the Origin header that was already mentioned in the StackOverflow post:

Origin: chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop

Turns out that IBM Connections doesn’t really like that. That’s by design and has something to do with cross-site request forgery.. Using a curl command I could easily bypass the header and confirm that it was indeed the cause of my problem.

So the only thing left (since I like testing with Postman), was to figure out how to change that Origin header. The header is one of the ‘restricted’ headers that is automatically added by the browser (Chrome) and can’t be easily changed. Luckily, the people at Postman also thought of that and created the “Postman Interceptor“: a Chrome extension that sits as a sort of proxy between your Postman requests. After enabling that in Postman I was able to change the Origin header of my requests. I set it to the hostname of the IBM Connections server and voila: happy times!

RESTless getting data from XPages to IBM Connections and back again

Recently I was working on getting data from IBM Connections in and out of an XPages application using the IBM Connections API. The API was great to work with: it is pretty good documented and easy to understand. It uses Atom feeds and RESTful calls to communicate.

I needed to implement the data read/write ‘barebones style’. No HTTPClient and no Abdera. Don’t ask me why. but it’s not because I like to torture myself. In the beginning that actually worked quite well: I was able to implement and parse the GET, PUT and DELETE calls without any big problems.

Until… I tried to create a File in Connection. According to the API this can be done in two ways: either by sending multipart form-data (including the encoded file) or just the file using a POST request. Since the multipart form-data option returns a JSON object (and everywhere else I worked with XML/ Atom), I went with the option to just post the file.

To test my calls and the API I was using the Dev HTTP Client Chrome plugin (which I can highly recommend!). Using that I could simulate the request: make a POST to the correct Files URL, select a file and of we go. Response code: 201. All fine.

I then tried the same in SSJS: create a HTTPUrlConnection, set the method to POST and write the file to an output stream. Response code: 503 (“service unavailable”). No matter what I did.

So I searched. And searched. And tested. And couldn’t figure out why it failed. Until I had a bright moment: check what actually’s being sent (headers and body) and compare it with the output of the Dev HTTP Client. For the plugin that was easy: F12 in Chrome and you’ll have all the information you need. For the server-to-server call it was more difficult. I ended up installing Wireshark to inspect the network traffic.

After I found the POST request (in the enermous amount of data Wireshark generates) I noticed something strange and was sure I didn’t add: a Content-Type header with the value application/x-www-form-urlencoded. That is obviously wrong: I’m sending a binary file. It shouldn’t add that header. There was a bug in Java that describes the same behaviour, but that was supposed to be fixed in a later 1.5 version. I (now) know that the Java 1.6 version in Domino is not Oracle’s one so might that explain why this issue (or is it a feature?) still exists.

The solution was easy: override that header with the correct one. I used the URLConnection.guessContentTypeFromName() function (yes, that really exist) and added the header. Response: 201. Every time. Happy Mark and client.