DEV Community

ShyGyver
ShyGyver

Posted on • Updated on

Generate documentation with @novice1/api-doc-generator: Part 1

In the previous articles, we went through:

Now we wish to use the API for ourself or give an access for other people to use. For that we are missing something of fundamental importance: documentation.

Let us be real, during my years as a developer, I never met anyone who liked writing documentation. That does not mean that it's not necessary to do so.
For a REST API, a schema of the API can be very useful and self explanatory. There are multiple schema specifications like OpenAPI and Postman. @novice1/api-doc-generator covers them both.

With @novice1/api-doc-generator, you can easily generate an OpenAPI and/or Postman schema from your application. That package is quite complete, covers all cases and has a reference sheet for its usage.

In this article we will see how to generate an OpenAPI schema with @novice1/api-doc-generator for a simple REST API.

Create the service

Let's install the dependencies

npm i @novice1/api-doc-generator yamljs
npm i --save-dev @types/yamljs
Enter fullscreen mode Exit fullscreen mode

and create the service that will generate the documentation

src/services/openapi/generator.ts

import { OpenAPI } from '@novice1/api-doc-generator';
import { EXTERNAL_PORT, EXTERNAL_PROTOCOL, HOSTNAME } from '../../config/server';

export const openAPIGenerator = new OpenAPI()
    .setTitle('API DOC')
    .setHost(`${EXTERNAL_PROTOCOL}://${HOSTNAME}${EXTERNAL_PORT ? ':'+EXTERNAL_PORT : ''}`)
    .setConsumes(['application/json'])
    .setTags([
        {
            name: 'default',
            externalDocs: { description: 'Find more info here', url: 'https://swagger.io/specification/' }
        }
    ])
Enter fullscreen mode Exit fullscreen mode

Access documentation

Using @novice1/app, the app provides metadata. Those are used to generate the REST API schema.

src/index.ts

import logger from '@novice1/logger';
import { app } from './app';
import { httpError, httpNotFound } from './middlewares/http';
import { PORT } from './config/server';
import { openAPIGenerator } from './services/openapi/generator';

// 404
app.use(httpNotFound);

// error
app.useError(httpError);

// start server
app.listen(PORT, () => {
    logger.info('Application running on port', PORT)

    /**
     * Add app metadata to API documentation generator
     */
    openAPIGenerator.add(app.meta)
})
Enter fullscreen mode Exit fullscreen mode

Create a route that renders the schema:

src/routes/documentation.ts

import routing from '@novice1/routing';
import Joi from 'joi';
import YAML from 'yamljs';
import { openAPIGenerator } from '../services/openapi/generator';

export default routing().get({
    path: '/documentation',
    parameters: {
        // query
        query: Joi.object().keys({
            json: Joi.boolean().default(false)
        }),
        // do not put this route in the documentation 
        undoc: true
    }
}, (req, res) => {
    // Get the JSON schema
    const result = openAPIGenerator.result()

    if (!req.query.json) {
        // respond with a yaml schema
        res.set('Content-Type', 'text/plain')
        res.send(YAML.stringify(result, 10, 2))
    } else {
        // respond with the JSON schema
        res.json(result)
    }
})
Enter fullscreen mode Exit fullscreen mode

And register it with the other routers:

src/routes/index.ts

import corsOptions from './cors-options';
import documentation from './documentation';
import helloWorld from './hello-world';
import items from './items';

// all routers
export default [
    corsOptions,
    documentation,
    helloWorld,
    items
]
Enter fullscreen mode Exit fullscreen mode

Now, we run the application to see if we have access to the schema at http://localhost:8080/documentation.

For development:

npm run dev
Enter fullscreen mode Exit fullscreen mode

For production:

npm run lint
npm run build
npm start
Enter fullscreen mode Exit fullscreen mode

It should render the schema in yaml format. To get the json format, we can set the following query string in the url ?json=true.

The schema can be copied and pasted to the Swagger Editor to get a UI to test your API.

Render swagger UI

If you want your API to not just serve the schema but also the UI, you can install the following dependencies:

npm i swagger-ui-express
npm i --save-dev @types/swagger-ui-express
Enter fullscreen mode Exit fullscreen mode

and change the route that serves the documentation like so:

src/routes/documentation.ts

import routing, { RequestHandler } from '@novice1/routing';
import Joi from 'joi';
import YAML from 'yamljs';
import swaggerUi from 'swagger-ui-express';
import { openAPIGenerator } from '../services/openapi/generator';

const swaggerUIController: RequestHandler = (req, res, next) => {
  const swaggerDocument = openAPIGenerator.result()
  return swaggerUi.setup(swaggerDocument)(req, res, next)
}

const swaggerRouter = routing()
  .get({
    path: '/',
    parameters: {
      undoc: true
    },
  },
  swaggerUIController)
  .get({
    path: '/schema',
    parameters: {
      query: Joi.object().keys({
        json: Joi.boolean().default(false),
      }).options({ allowUnknown: true, stripUnknown: false }),

      undoc: true
    }
  }, (req, res) => {
    const result = openAPIGenerator.result();

    if (!req.query.json) {
      res.set('Content-Type', 'text/plain');
      res.send(YAML.stringify(result, 10, 2));
    } else {
      res.json(result);
    }
  });

export default routing().use('/documentation', 
  swaggerUi.serve, 
  swaggerRouter
);
Enter fullscreen mode Exit fullscreen mode

That way, your API will serve the UI (html) at /documentation and the schema (yaml/json) at /documentation/schema.

As I said earlier, @novice1/api-doc-generator is quite complete. We can define everything there is in OpenAPI Specification 3.0.3 and Postman Collection Format v2.1.0 so it would be impossible to cover it all in one article. As of today, the best way to learn @novice1/api-doc-generator is by reading the package's documentation that you can find here. It lists and defines the classes, interfaces, enumerations and gives a few examples on how to define authorizations, responses, etc ...
I would gladly talk about more aspects of the package in future articles if it is requested in the comment section.
What is sure is that we will continue using and updating our REST API documentation in the next article that will be about Authorizations with @novice1/app.

References

You can see the result of what we have done till now right here on Github.

Top comments (0)