Creating mock RESTful APIs using Sandbox

While browsing through my Twitter feed a couple of days ago I saw someone mentioning Sandbox, a Software as a Service (SaaS) solution for quick creation and deployment of mock services for development and testing purposes. After starting to play around with it a bit, I was rather impressed by the ease with which one can create useful mocks from Swagger, RAML and WSDL API specifications.

As an example, I created a RAML API model for a simple API that shows information about test tools. Consumers of this API can create, read, update and delete entries in the list. The API contains six different operations:

  • Add a test tool to the list
  • Delete a test tool from the list
  • Get information about a specific test tool from the list
  • Update information for a specific test tool
  • Retrieve the complete list of test tools
  • Delete the complete list of test tools

You can view the complete RAML specification for this API here.

Creating a skeleton for the mock API in Sandbox is as easy as registering and then loading the RAML specification into Sandbox:
Loading the RAML specification in SandboxSandbox then generates a fully functioning API skeleton based on the RAML:
API operations from the RAMLSandbox also creates a routing routine for every operation:

var testtools = require("./routes/testtools.js")

/* Route definition styles:
 *
 *	define(path, method, function)
 *	soap(path, soapAction, function)
 *
 */
Sandbox.define("/testtools", "POST", testtools.postTesttools);
Sandbox.define("/testtools", "GET", testtools.getTesttools);
Sandbox.define("/testtools", "DELETE", testtools.deleteTesttools);
Sandbox.define("/testtools/{toolname}", "GET", testtools.getTesttools2);
Sandbox.define("/testtools/{toolname}", "PUT", testtools.putTesttools);
Sandbox.define("/testtools/{toolname}", "DELETE", testtools.deleteTesttools2);

and empty responses for every operation (these are the responses for the first two operations):

/*
 * POST /testtools
 *
 * Parameters (body params accessible on req.body for JSON, req.xmlDoc for XML):
 *
 */
exports.postTesttools = function(req, res) {
	res.status(200);

	// set response body and send
	res.send('');
};

/*
 * GET /testtools
 *
 * Parameters (named path params accessible on req.params and query params on req.query):
 *
 * q(type: string) - query parameter - Search phrase to look for test tools
 */
exports.getTesttools = function(req, res) {
	res.status(200);

	// set response body and send
	res.type('json');
	res.render('testtools_getTesttools');
};

Sandbox also creates template responses (these are rendered using res.render(‘testtools_getTesttools’) in the example above). These are mostly useful when dealing with either very large JSON responses or with XML responses, though, and as our example API has neither, we won’t use them here.

To show that the generated API skeleton is fully working, we can simply send a GET to the mock URL and verify that we get a response:
Testing the generated API skeletonNow that we’ve seen our API in action, it’s time to implement the operations to have the mock return more meaningful responses. We also want to add some state to be able to store new entries to our test tool list for later reference. For example, to add a test tool submitted using a POST to our list – after verifying that all parameters have been assigned a value – we use the following implemenation for the export.postTesttools method:

/*
 * POST /testtools
 *
 */
exports.postTesttools = function(req, res) {
    
    if (req.body.name === undefined) {
        return res.json(400, { status: "error", details: "missing tool name" });
    }
    
    if (req.body.description === undefined) {
        return res.json(400, { status: "error", details: "missing tool description" });
    }
    
    if (req.body.url === undefined) {
        return res.json(400, { status: "error", details: "missing tool website" });
    }
    
    if (req.body.opensource === undefined) {
        return res.json(400, { status: "error", details: "missing tool opensource indicator" });
    }

    // add tool to list of tools
    state.tools.push(req.body);
    
    return res.json(200, { status: "ok", details: req.body.name + " successfully added to list" });
};

Likewise, I’ve added meaningful implementations for all other methods. The complete code for our mock API implementation can be found here.

Finally, to prove that the mock API works as desired, I wrote a couple of quick tests using REST Assured. Here’s a couple of them:

// base URL for our Sandbox testtools API
static String baseUrl = "http://testtools.getsandbox.com/testtools";
	
// this is added to the URL to perform actions on a specific item in the list
static String testtoolParameter = "/awesometool";
	
// original JSON body for adding a test tool to the list 
static String testtoolJson = "{\"name\":\"awesometool\",\"description\":\"This is an awesome test tool.\",\"url\":\"http://awesometool.com\",\"opensource\":\"true\"}";
	
// JSON body used to update an existing test tool
static String updatedTesttoolJson = "{\"name\":\"awesometool\",\"description\":\"This is an awesome test tool.\",\"url\":\"http://awesometool.com\",\"opensource\":\"false\"}";

@BeforeMethod
public void clearList() {
		
	// clear the list of test tools
	delete(baseUrl);
		
	// add an initial test tool to the list
	given().
		contentType("application/json").
		body(testtoolJson).
	when().			
		post(baseUrl).
	then();
}

@Test
public static void testGetAll() {
		
	// verify that a test tool is in the list of test tools
	given().
	when().
		get(baseUrl).
	then().
		body("name", hasItem("awesometool"));
}

@Test
public static void testDeleteAll() {
		
	// verify that the list is empty after a HTTP DELETE		
	given().
	when().
		delete(baseUrl).
	then().
		statusCode(200);
	
	given().
	when().
		get(baseUrl).
	then().
		body(equalTo("[]"));
}

An Eclipse project containing all of the tests I’ve written (there really aren’t that many, by the way, but I can think of a lot more) can be downloaded here.

One final note: Sandbox is a commercial SaaS solution, and therefore requires you to fork over some money if you want to use it in a serious manner. For demonstration and learning purposes, however, their free plan works fine.

Overall, I’ve found Sandbox to be a great platform for rapidly creating useful mock API implementation, especially when you want to simulate RESTful services. I’m not sure whether it works as well when you’re working with XML services, because it seems a little more cmplicated to construct meaningful responses without creating just a bunch of prepared semi-fixed responses. Having said that, I’m pretty impressed with what Sandbox does and I’ll surely play around with it some more in the future.

Testing RESTful webservices

With the world of IT systems and applications becoming more and more distributed, testing the interfaces between system components becomes ever more important. In a previous post I have introduced a very basic way to test a SOAP web service interface. However, nowadays, in the world of APIs, the REpresentational State Transfer or REST standard becomes increasingly popular due to its lightweight nature. This article introduces a way to test RESTful APIs in a simple yet effective manner, and in a way that integrates smoothly with your existing Java-based testing frameworks, such as those based on Selenium Webdriver.

RESTful APIs come in several varieties. In this post, we are going to see two of them: one returning XML responses (I used this one) and one returning JSON responses (I used this one). You’re welcome to click on either link to see the difference in response format.

Also, I have used some external libraries to get the code to work:

Verify the HTTP status code
The first thing we are going to test for our services is whether they respond to our requests at all. This means we are going to validate whether the HTTP response code for the REST service is correct. There way to do this is equal for both XML and JSON REST APIs:

public static void testStatusCode(String restURL) throws ClientProtocolException, IOException {

	HttpUriRequest request = new HttpGet(restURL);
	HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request);
		
	Assert.assertEquals(httpResponse.getStatusLine().getStatusCode(),HttpStatus.SC_OK);
}

Pretty simple, right? As you probably know, calling a RESTful API is done by either sending a HTTP POST or a HTTP GET to a specific URL. This in contrast with SOAP web services, where you send a specific XML message to an endpoint. Then, retrieve the HTTP status code from the response and check whether this is OK (i.e., equal to HTTP 200).

Verify the response content type
Next, we are going to verify whether our web service sends us the content type we expect (either XML or JSON). Again, this can be done with just a couple of lines of code:

public static void testMimeType(String restURL, String expectedMimeType) throws ClientProtocolException, IOException {
		
	HttpUriRequest request = new HttpGet(restURL);
	HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request);
		
	Assert.assertEquals(expectedMimeType,ContentType.getOrDefault(httpResponse.getEntity()).getMimeType());
}

Again, just call the RESTful API URL and retrieve the information you need from the response. In this case, we are interested in the MIME type, which should be either ‘application/xml’ or ‘application/json’, depending on the URL we use.

Verify the response content
Now that we have verified whether our services return correct responses with the correct MIME type, it’s time to look at the actual content of the response. This is where testing XML RESTful APIs differs from testing JSON RESTful APIs, since we need to parse the response to extract the elements and element values we’re interested in.

For XML, we can do this using the following piece of code:

public static void testContent(String restURL, String element, String expectedValue) throws ClientProtocolException, IOException, SAXException, ParserConfigurationException {
		
	Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(restURL);
	NodeList nodelist = doc.getElementsByTagName(element);
		
	Assert.assertEquals(expectedValue,nodelist.item(0).getTextContent());		
}

Note that we use a different way to retrieve the result from the REST URL as we need to parse it as actual XML. After we’ve done that, we simply look for the XML element we’re interested in and compare its value to the value we expect.

For JSON, we can verify element values as follows:

public static void testContentJSON(String restURL, String element, String expectedValue) throws ClientProtocolException, IOException, SAXException, ParserConfigurationException, JSONException {

	HttpUriRequest request = new HttpGet(restURL);
	HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request);

	// Convert the response to a String format
	String result = EntityUtils.toString(httpResponse.getEntity());

	// Convert the result as a String to a JSON object
	JSONObject jo = new JSONObject(result);

	Assert.assertEquals(expectedValue, jo.getString(element));
}

Here, we need to take an intermediate step to parse the response to a sensible format. First, we convert the HttpResponse to a String, then we convert this String to a JSONObject. From this JSONObject we can then extract the value for a specific element and compare it to an expected value.

The above examples should get you started nicely when you’re asked to include testing RESTful web services in your automated testing solutions.

Again, happy testing!

An example Eclipse project where I use the code above can be downloaded here.