Documentation generation

When I was first investigating Node frameworks for building an API, documentation generation was a hugely important feature that I needed. I was building a public API for a proprietary system at the time. Without good documentation, this, or any API, wouldn't garner much usage as you can probably imagine.

As the initial writing of API documentation is a huge chore, one which I don't enjoy anyway, the even more time consuming task is to constantly try to update documentation to keep it in sync with the latest version of the API. For an API under constant development, this would become a huge time sink, and so drove the need for documentation generation. In most frameworks, this generally comes from requiring annotations, and/or compromising the flexibility of route configuration, which aren't great options.

Fortunately, the configuration-over-code approach of hapi lends itself quite well to being able to generate documentation, as we can generate a full routing table with all the route configuration attached, as we have seen with blipp. If you read the blipp source code (https://github.com/danielb2/blipp/blob/master/lib/index.js), you can see it's not very complicated to read the routing table configuration. Can you imagine what this would be like if it were trying to interpret configuration from code as opposed to configuration?

This means we can now generate a JavaScript or JSON representation of all our routes as well as all the inputs that they accept from our attached validation, apart from any description, tags, or notes attached. There are two widely-used libraries that avail of this approach to turn this representation of our routes into a viewable HTML page generated on each startup of our server. These libraries are lout, developed by the hapi team (https://github.com/hapijs/lout), and hapi-swagger (https://github.com/glennjones/hapi-swagger). Both use different strategies to achieve the goal of generating route documentation.

lout iterates through the hapi server routing table and creates a JavaScript object, which it passes to a template context (as we saw in Chapter 2, Adding Functionality by Routing Requests, when using the vision module) to serve a template. This works well, and provides a basic view of your routing table with all its input validation rules.

hapi-swagger creates our documentation via the swagger library (http://swagger.io/swagger-ui/). It cleverly uses our route configuration to create a swagger-compliant JSON specification of our routes. It then provides a route with an HTML page that loads the swagger-ui JavaScript library, which reads in the JSON specification. Through this, the documentation page is created (which is an interactive sandbox) so that you can test all your API endpoints right from this documentation page. I've found that this is a hugely useful feature to have as part of an API to drive adoption, and it saves countless developer hours updating documentation.

Looking again at our user store API example, let's see what effort is required to make our API self-documenting, based on all the validation we have added in this chapter. For this example, we'll use the hapi-swagger library to document our API, as this will then give us a sandbox to test any API functionality we add right from the page. Let's get started.

First we need to install the hapi-swagger library. We also need to install the inert and vision libraries, as we will be serving some static files as well as templates. Let's do that now:

$ npm install hapi-swagger inert vision

Next, we'll modify the index.js file of our user store. We need to require the hapi-swagger, inert, and vision modules, then register them as plugins against our server. Let's look at the resulting index.js with these modifications applied:

'use strict';
const Hapi = require('hapi');
const Blipp = require('blipp');
const HapiLevel = require('hapi-level');
const UserStore = require('./user-store.js');
const HapiSwagger = require('hapi-swagger');
const Inert = require('inert');
const Vision = require('vision');
const server = new Hapi.Server();
server.connection({ port: 1337, host: '127.0.0.1' });
server.register([
  { register: HapiLevel, options: { path: './temp', config: { valueEncoding: 'json' } } },
  UserStore,
  Blipp,
  Inert,
  Vision,
  HapiSwagger
], (err) => {
  // handler err
  server.start((err) => {
    // handler err
    console.log(`Server running at ${server.info.uri}`);
  });
});

It's worth noting the importance of handling errors here. In this example, I omit them for brevity, but if you hadn't handled the error when registering plugins or starting your server for example, and were missing one of hapi-swagger's dependencies such as inert or vision, the server would just exit without an error, in a hard-to-debug fashion. The lesson to be learned: always handle the errors in your callbacks!

Other than that, there's nothing too drastic here. Now as the hapi-swagger documentation specifies, it will only document the routes that have an api tag added to the route configuration. So, let's that make that change in our user-store.js file as well. This would mean modifying our GET route configuration as follows:

server.route([
  {
    method: 'GET',
    path: '/user/{userId}',
    config: {
      validate: { … },
      handler: function (request, reply) { … },
      response: { … },
      description: 'Retrieve a user',
      tags: ['api']       // API Tag added.
    }
});

It would also mean doing the same for our POST route. If we launch our hapi application now, we will see that we have some extra routes added in our blipp output as seen in the following screenshot:

Documentation generation

These are just routes for serving some of the necessary static content for our generated documentation page. That /documentation page looks interesting, though; let's open that up in a browser, and see what we get:

Documentation generation

And there we have it—an interactive documentation sandbox with our expected model schema on the right. If you check the GET route documentation, it also lists the expected response schema that we added earlier in the chapter.

For the full range of options in configuring the generated hapi-swagger documentation page, I recommend reading the hapi-swagger repo documentation.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.162.49