-
Notifications
You must be signed in to change notification settings - Fork 11
Testing RESTful APIs
Before attempting this tutorial, make sure you've read and understood the contents in Getting Started.
This tutorial corresponds to example #2 in the legion-starter-pack. In this tutorial, we will:
- Introduce a new app in legion-obstacle-course (our toy server for these tutorials) called "ticket."
- Use legion to make RESTful JSON calls to the toy server.
Instead of using the raw legion-io-fetch API, we'll be using a tiny convenience-version of the API designed for RESTful JSON.
const rest = require('legion-io-fetch').rest;
Unlike the core fetch API, which is completely generic, this rest API specializes to the various RESTful HTTP methods (GET, POST, PUT, PATCH, DELETE) as individual javascript function calls. It also automatically stringifies and uploads your javascript objects as JSON content for all methods except GET.
The ticket app (/ticket) is a part of legion-obstacle-course that lets us create and redeem tickets. By calling /ticket/new we get a JSON object with a new ticket number. By calling /ticket/redeem we can redeem the same ticket. Tickets can only be redeemed once. In real life, a ticket might be a session identifier, and redeeming the ticket might mean closing the session.
In any load test we need to validate each response to make sure that it is consistent with our expectations. Otherwise, we can not trust that the test results represent a successful outcome. To this end, we start by writing a validation method:
function assertSuccess(response) {
if( !response.ok )
throw new Error('Response was not Ok.');
if( response.json.status !== 'success' )
throw new Error( response.json.status + ': ' + response.json.reason );
return response;
}
We just assert that the status of a response is OK and the JSON payload also reports a success. If either of those conditions are not met, we throw an error with an informative method.
Note that assertSuccess() returns its own argument. This means we can pass it through chain() and still use the response for something else.
Our testcase will be structured a lot like a chain of then()-able calls in a Promise-based API. We'll start by making a request and use the chain() method to add subsequent steps to follow after that request. Each method that we pass to chain() receives a single argument, which is the output of the previous step in the chain.
.testcase(L.of()
.chain(rest.post(host + '/ticket/new'))
.chain(assertSuccess)
.chain(response => rest.post(host + '/ticket/redeem?ticket='+ response.json.ticket))
.chain(assertSuccess))
We call localhost/ticket/new to get a new ticket and validate the response. The response to this call will contain a JSON object with a ticket field containing the unique ID of our new ticket. Then we call localhost/ticket/redeem and use the ticket field of the previous request as a query parameter. If this fails for some reason, perhaps because our ticket number is invalid, then the final call to assertSuccess() will detect the error and throw an exception.
We use the main() method to wrap this testcase into an executable program. You can run it from the starter pack by calling:
node examples/002_ticket.js
If you want to run multiple simultaneous users, try this, which will run the testcase 10 times in parallel:
node examples/002_ticket.js -n 10