Tuesday, 15 September 2015

Prototyping usage of an OAUTH API

There are many services out there that offer an OAUTH2 API - whereby you get an access token, associated to your account, and you use that with requests rather than logging in each request. It's a solid design, because for one, you as a user can opt to grant permission to parts of the system, and for another you can easily revoke access to individual applications.

One problem? It is fairly unlikely there is a client library built for PL/SQL or APEX use. For instance, Google provides libraries for[1]:
  1. Java
  2. JavaScript
  3. .NET
  4. PHP
  5. Python
  6. Objective-C
Another example, Instagram provides[2]:
  1. Python
  2. Ruby
It's not too hard to build it in PL/SQL once you understand the flow of OAUTH. I started working on one for Google services, which is hosted over on my GitHub profile. Before you get too far with that though, you may like to test the requests you are attempting to work with. The one's I have seen tend to provide an API test tool, however you may like to create templates that you can use down the track without relying on their test tools.

So here, I'd like to introduce you to a neat little tool called Postman. I'm sure there are quite similar apps out there, but I'll be focusing on this particular tool. This is an app that is actually available through the Chrome Web Store[3]. And because it's an app offered through the Chrome Web Store, it is cross platform - and you can just launch it from your system launcher - you need not even know its a chrome app!

Since I already have a Google library, I'll focus on the Instagram API. The business case I have is that I've posted a comment on someone's post, and I want to track it down with their API (my goal was to delete it, but Instagram only offers access to additional scopes for applications that have been submitted for review[4] - you can get basic access to Instagram though). The API doesn't offer an endpoint for comments you've posted, but you can list comments on particular media objects, to locate it that way.

The first step with any OAUTH project is to set up a client, where you can give it a name and in turn get a client id and client secret, that are needed for fetching the access token that needs to be sent with each request. Note: A lot of the Instagram requests simply require use of the client id, but for the purposes of this example, I will be fetching the access token and using that in the requests.

As you can see with the redirect URI, you can use a URL suggested by postman so that you can successfully fetch the token in the app. The other bit of information you need before requesting a token, is what scopes you would like access to. You can review available scopes for Instagram by looking at the authentication documentation[5].

So, on your request builder, within the authorization tab you can select which authentication you need. If you change that to OAuth 2.0, you will see a button "Get access token". Click that, and fill out all the required fields. If you review the authentication documentation, you will see that the authorization base URL is https://api.instagram.com/oauth/authorize/ and the access token URL is https://api.instagram.com/oauth/access_token. So, we populate that information and specify the scope "basic comments". If all goes well, you should get a success result along with the token.

Once you save the token with a convenient name, it will appear in the authorization tab where you can either add it to the URL or as a request header. The Instagram API works with the token in the URL as a URL parameter, so you will need to add it there. Once you have the request URL defined (e.g. https://api.instagram.com/v1/users/self/) ensure the radio is selected "Add token to URL" and click the recently saved token "Instagram token". 

So now to prototype the actual task you're attempting to perform. By looking at the list of available endpoints[6] you can start to figure out which end points you might need to perform the desired task. Looking at the comments endpoint, you will notice it has a DEL operation, which accepts two paramaters:
  1. media id
  2. comment id
So, from here you will need to find these two identifiers. If you know the shortcode for the media, \youI can perform a request using the /media/shortcode/[code] endpoint. Or if you know the user, you can search to find their user id using the /users/search endpoint, then list their recent media, and get the id of the media that way.

Once you have the media id, you need to figure out the comment id. This can be done through the /media/[media-id]/comments endpoint. Though, it is worth noting that Instagram seems to only return 150 of the most recent comments. 

Once you find the two bits of information, you can then delete the comment (obviously, you can only delete comments you have authored or comments on your own posts). The good thing about Postman is that it allows you to save requests in set collections, so you can easily repeat the process again.

For simplicity, I'll go with the shortcode method of determining the media ID. I attached a comment to media with shortcode: 54-EW8IaHO, giving us the first request URL of: https://api.instagram.com/v1/media/shortcode/54-EW8IaHO. Here, I find that the media id is: 1042856292129022414_528817151.

The next step, is to get the comments. I compile a new request, to https://api.instagram.com/v1/media/1042856292129022414_528817151/comments. From there, scrolling to the end of the response, I can see my comment has the ID 1074977853463962032. In reality, you would need to provide some means of iterating of the returned comments.

Finally, we can compile the DELETE request using the aforementioned identifiers, giving us the request: https://api.instagram.com/v1/media/1042856292129022414_528817151/comments/1074977853463962032

As previously mentioned, this specific request isn't possible without Instagram first reviewing your application - but the general idea is there.

Since you can save the request templates, you can easily go back in to repeat any processes you set up as an extra means to debug when your developed solution isn't working as expected - could be useful if there are any API changes. I set up a collection called Instagram, and added all related requests in there.

Once you have the flow prototyped, it should more straightforward to convert it into some functions/procedures in your Oracle application (or other system if no client libraries are unavailable).