Give your Node APIs some Swagger

A lot of API development can be quite boilerplate and copy paste heavy. Swagger-node is a module which provides a robust set of tools to build APIs in Node.js....

a year ago

Latest Post Automatic Offline Backup With a Raspberry Pi by Tyler Moon

A lot of API development can be quite boilerplate and copy paste heavy. There is also a lot of flexability in how an API can be built which means it can be difficult to set standards. Swagger (Now known as OpenAPI) is a set of HTTP API standards which attempts to straighten out the wild west of API development. Swagger-node is a module which provides a robust set of tools to build APIs in Node.js. It helps with designing, testing, and building Swagger complaint APIs. Swagger-node has skeletons built for Express, Hapi, Restify, and Sails.

In this example we are going to build a simple Swagger-compliant API using Swagger-node and restify. Its going to have two basic endpoints, /hello-world and /add, with the former being generated by the module and the later being written.

Prerequisites

Setup

Start out by installing the swagger-node NPM package

npm install -g swagger

And then use swagger to create a new API project. Select the restify option when the dialog for which Node framework you want to choose comes up.

Note: This create command will create a new directory called hello-world at the current directory
swagger project create hello-world
> restify

And there you go a whole API with a test project and documentation is already built!

Swagger Configuration

Now lets go ahead and dive into the Swagger documentation / configuration. There is a handy built in server to help configure the documentation in real time. This documentation also defines the structure of your API and allows for parameter checking and error handling.

swagger project edit

There should now be a brower window open with something like the following

Swagger Documentation Editor

On the right side is an editor for the YAML config file, and on the left is a live preview of your API documentation. This is a really powerful tool as API projects get bigger or if you bring new developers onto the project.

Below the x-swagger-pipe: swagger_raw line add the following YAML that defines a new endpoint on a new controller that we will make in a few.

  /add:
    x-swagger-router-controller: add
    get:
      description: Returns the sum of the two given numbers
      operationId: add
      parameters:
        - name: numA
          in: query
          description: The first number to add
          required: false
          type: integer
        - name: numB
          in: query
          description: The second number to add
          required: false
          type: integer
      responses:
        "200":
          description: Success
          schema:
            # a pointer to a definition
            $ref: "#/definitions/AddResponse"
        # responses may fall through to errors
        default:
          description: Error
          schema:
            $ref: "#/definitions/ErrorResponse"

And we will need a new definition for a return object so add the following to the bottom of the YAML file

  AddResponse:
    required:
      - message
    properties:
      message:
        type: string

Now the documentation on the right should show a new /add endpoint that takes in two numbers and returns the AddResponse which has a message response field. This object could contain multiple fields if needed.

Test Driven Development Time

In case you have not heard of TDD (Test Driven Development) before it is a programming development methodology where you start with unit test and then write code so that test passes. Initially your tests will all fail but as you write the code they will pass and then you are certain that you have good test coverage. This test coverage comes into play when refactoring or when implementing a CI/CD pipeline.

Lets start by adding a new Node file /test/api/controllers/add.js to test our add controller and endpoint which we just defined above but have not implemented yet. Then add the following Node.js code to the new file.

// add.js (tests)
var should = require('should');
var request = require('supertest');
var server = require('../../../app');

// Testing a controller
describe('controllers', function() {
  // Specifically the add controller
  describe('add', function() {
    // And the GET /add endpoint on the add controller
    describe('GET /add', function() {
      // Make a request with two paramters and expect them to be summed in the response
      it('should accept two parameters', function(done) {
        request(server)
          .get('/add')
          .query({ numA: 1, numB: 2})
          .set('Accept', 'application/json')
          .expect('Content-Type', /json/)
          .expect(200)
          .end(function(err, res){
            should.not.exist(err);

            res.body.should.eql('Result: 3');

            done();
          });
      });
      // Make a request with no paramaters and expect the default response
      it('should return a default string', function(done){
        request(server)
          .get('/add')
          .set('Accept', 'application/json')
          .expect('Content-Type', /json/)
          .expect(200)
          .end(function(err, res){
            should.not.exist(err);

            res.body.should.eql('Result: 0');

            done();
          });
      });
    });
  });
});

Because Swagger already setup the test project that is all we need to get our testing efforts going. Lets go ahead and run the swagger project test command so we can be sure everything runs. We are expecting 2 passing tests (For the hello-world endpoint the skeleton setup) and 2 failing tests that we just wrote.

swagger project test
Should have two failing tests :(

Add the Add Controller

In order to fix our failing tests we need to actually write out our controller that we have already defined in our documentation and written our tests for. Add a Node.js file /api/controllers/add.js to define our new controller.

Note: The test project and the API have the same structure which makes it easy to see which tests are for which controllers
// add.js (API)
'use strict';
var util = require('util');
module.exports = {
  add:add
};

function add(req, res) {
  var numA = req.swagger.params.numA.value || 0;
  var numB = req.swagger.params.numB.value || 0;
  var sum = numA + numB;
  var response = util.format('Result: %d', sum);
  res.json(response);
}

And now we have our controller and endpoint setup. Time to run our tests again with swagger project test which should result in something like the following

Only 1 failing test now

While one of our tests is passing one is not! Its returning a 400 "Bad Request" instead of a 200 "OK" response which is not what is expected. Open up http://127.0.0.1:10010/add in your browser to get a better message from that response.

You should get something like the following

{"message":"Request validation failed: Parameter (numA) is required","code":"REQUIRED","failedValidation":true,"path":["paths","/add","get","parameters","0"],"paramName":"numA"}

We marked both of the parameters for the add endpoint as required in the swagger documentation however our test is not providing either of them. Boom input validation! Now we could either change the documentation or the tests to match the expected business case. In this instance lets change the documentation. swagger project edit will open up the documentation editor again and this time change the required: true values for the add parameters to required: false.

Running swagger project test again should result in the following.

All green!

And now all of our tests are passing. This is the best part of TDD when you know for a fact that your code works as it should and you also have full test coverage.

Using the following command will launch the API server

swagger project start

And you should be able to hit http://localhost:10010/add?numA=1&numB=2 and get a response saying 3.

Summary

In this project we saw how to build a Node.js restify API quickly and easily using swagger-node. The swagger documentation editor, tests, and overall project structure make it very easy to build APIs without the normal copy paste and inevitable spaghetti code. And we did a little TDD along the way!

Tyler Moon

Published a year ago

Comments?

Leave us your opinion.