Workflow: Generating an OAS File From Your Code

OAS/Swagger provides us with a standardized way to document APIs, giving us a format which can be accepted by a multitude of tools to produce (largely) the same results. This is great! Open formats mean that we save time by not reinventing the wheel and every company creating its own standards.

OAS files are only useful if they stay up to date. If they fall out of sync from how your actual API works, then your users will get frustrated as they attempt to use your API in weird, wrong or legacy ways. Keeping your users happy should be of the utmost importance as an API producer.

What's the best way to keep your OAS file up to date? Automatically generating it straight from your code! If you're hand-editing your file, the chance for changes to not be replicated in both places increase significantly. To help with this problem at ReadMe, we built swagger-inline. Swagger-inline uses code comments to document your API, like so:

const express = require('express');
const app = express();

/*
 * @api [get] /pets
 * description: Returns all pets from the system that the user has access to
 * responses:
 *   200:
 *     description: A list of pets.
 */
app.get('/pets', function() {
    /* Pet code */
});

These comments are just OAS Path Operations in yaml format and should support everything that is supported in OAS 3.

Given the above code snippet, and a base OAS file:

{
   "openapi": "3.0.0",
   "info": {
      "description": "Pets API",
      "version": "1.0.0",
      "title": "petsapi.com"
   },
   "paths": {},
   "servers": [
      {
         "url": "http://petsapi.example.com"
      }
   ]
}

You can generate an OAS file like so:

npx swagger-inline './*.js' --base ./openapiBase.json --out openapi.json

(If you do not have npx, you can npm install and run it from ./node_modules/.bin/swagger-inline.)

This will output a openapi.json file like the following:

{
   "openapi": "3.0.0",
   "info": {
      "description": "Pets API",
      "version": "1.0.0",
      "title": "petsapi.com"
   },
   "paths": {
      "/pets": {
         "get": {
            "description": "Returns all pets from the system that the user has access to",
            "responses": {
               "200": {
                  "description": "A list of pets."
               }
            }
         }
      }
   },
   "servers": [
      {
         "url": "http://petsapi.example.com"
      }
   ]
}

It's best to add this as a "pretest" hook in your npm scripts, to make sure you're always generating the latest `openapi.json` file and validating it. Like so:

"scripts": {
  "pretest": "swagger-inline './*.js' --base ./bin/swaggerBase.json --out swagger.json && swagger-cli validate swagger.json",
}

You can then host it on your server for others to consume or upload it to ReadMe for us to build out your reference docs.

This isn't perfect as you may forget to update your comments in the same way you may forget to update your hand-crafted Swagger file. We've found this isn't the case for us, but YMMV. We may in the future look to auto generating the full definitions as a combination of express routes/mongoose models. We didn't want to do this initially as it feels too coupled to specific technologies.

If you're looking for a place to host your Swagger files, we've got that too! Read more here: https://blog.readme.io/documenting-your-api-in-your-code-with-swagger/.

Stay In-Touch

Want to hear from us about APIs, documentation, DX and what's new at ReadMe?