Accessing Custom APIs on Microsoft Azure Mobile Services


Needing some REST - 78/365 by Sergio Alvarez, on Flickr

Needing some REST – 78/365 by Sergio Alvarez, on Flickr

For my current project, I’m developing a Restful Web API using Microsoft Azure Mobile Services. These APIs are intended to be consumed by a mobile application, which is being developed in parallel by another team. On the server side, we’re doing our best to design the system along Restful best practice, so we’re using HTTP methods as appropriate, e.g. POST, PUT, PATCH, GET, DELETE, etc.

We recently ran into an integration problem, as our mobile app development team couldn’t access any APIs using the PUT method. This is the story of how we resolved this issue…

The root cause, as such, was some poor documentation of the Mobile Services Client Library, published by Microsoft.  At the time of writing, the invokeApi method which the mobile app team use to access our APIs documents the following HTTP methods: get, post, patch, update and delete.

Since ‘update’ is not a standard HTTP method, we assumed that it was being mapped either to PUT or PATCH, as either could apply.  Since some of our APIs specifically use PUT, then we needed to know how to access these APIs from the mobile client.

After several days to and fro with Microsoft Support, without any progress on the issue, I set up a test to see which methods were supported by the client library, and how to use them.

On the server side, I set up a test URL, with handlers for each of the supported http methods.  We’re using the Javascript server option, so server side code is running on Node.js. An example of the server side code is given here:

exports.register = function ( service ) {

logger.log( 'service routing entry point' );

    service.get( '/test', getTest );
    service.post( '/test', postTest );
    service.patch( '/test', patchTest );
    service.put( '/test', putTest );
    service.del( '/test', deleteTest );
};

function getTest ( req, res ) {
    logger.log( "/service/test GET handler" );
    res.send( 200, "HTTP-GET Handler" );
};

function postTest ( req, res ) {
    logger.log( "/service/test POST handler" );
    res.send( 200, "HTTP-POST Handler" );
};

function patchTest ( req, res ) {
    logger.log( "/service/test PATCH handler" );
    res.send( 200, "HTTP-PATCH Handler" );
};

function putTest ( req, res ) {
    logger.log( "/service/test PUT handler" );
    res.send( 200, "HTTP-PUT Handler" );
};

function deleteTest ( req, res ) {
    logger.log( "/service/test DELETE handler" );
    res.send( 200, "HTTP-DELETE Handler" );
};

Client side code was a single html page, using some embedded javascript that depended on the Mobile Service Client Library. This is given here, with the application url and application key substituted. You’ll need to replace these if you intend to use this code.

<html>
<head>
<script src='http://ajax.aspnetcdn.com/ajax/mobileservices/MobileServices.Web-1.1.2.min.js'></script>
<script>
var MobileServiceClient = WindowsAzure.MobileServiceClient;
var client = new MobileServiceClient('APP_URL', 'APP_KEY');

// GET
var get = function() {
	console.log("Making GET request");
	client.invokeApi("/service/test", {
		body: null,
		method: "GET"
	}).done( function(results) {
		console.log(results.response);
		alert(results.response);
	}, function (error) {
		console.log("GET ERROR: "+error.message);
	});
};

// POST
var post = function() {
	console.log("Making POST request");
	client.invokeApi("/service/test", {
		body: null,
		method: "POST"
	}).done( function(results) {
		console.log(results.response);
		alert(results.response);
	}, function (error) {
		console.log("POST ERROR: "+error.message);
	});
};

// PUT
var put = function() {
	console.log("Making PUT request");
	client.invokeApi("/service/test", {
		body: null,
		method: "PUT"
	}).done( function(results) {
		console.log(results.response);
		alert(results.response);
	}, function (error) {
		console.log("PUT ERROR: "+error.message);
	});
};

// PATCH
var patch = function() {
	console.log("Making PATCH request");
	client.invokeApi("/service/test", {
		body: null,
		method: "PATCH"
	}).done( function(results) {
		console.log(results.response);
		alert(results.response);
	}, function (error) {
		console.log("PATCH ERROR: "+error.message);
	});
};

// DELETE
var del = function() {
console.log("Making DELETE request");
	client.invokeApi("/service/test", {
		body: null,
		method: "DELETE"
	}).done( function(results) {
		console.log(results.response);
		alert(results.response);
	}, function (error) {
		console.log("DELETE ERROR: "+error.message);
	});
};

// UPDATE
var update = function() {
	console.log("Making UPDATE request");
	client.invokeApi("/service/test", {
		body: null,
		method: "update"
	}).done( function(results) {
		console.log(results.response);
		alert(results.response);
	}, function (error) {
		console.log("UPDATE ERROR: "+error.message);
	});
};
get();
post();
put();
patch();
update();
del();
</script>
</head>
<body>
</body>
</html>

Testing using the javascript console on a browser showed that all standard http methods are supported (GET, PUT, POST, PATCH and DELETE). The ‘update’ method always failed, presumably as it is not a standard HTTP method.

Good quality documentation matters. I’ve had to spend several days unnecessarily trying to figure this out, when good documentation in the first place would have saved me the time. In the original documentation, the ‘put’ method was not documented, but was supported, while the ‘update’ method is documented, but doesn’t work.

Advertisements

Tags: , , , , , , , , ,

%d bloggers like this: