How To Create a Trusted Web API Spec

At Springworks, we’re building ecosystems for connected cars. 
Connected cars generate huge amounts of data, which needs to be made accessible for end-user applications.

We primarily build domain-specific REST API:s to read and write data, making APIs central in our development.

We weren’t happy with our previous setup, where developers were expected to manually update README.md with API documentation as part of pull requests.

This lead to documentation not always being correct → confusion & waste of time. And avoiding wasted time is one of our most important objectives within development, to stay competitive even as a fairly small company.

We had one main objective when trying to resolve these issues:

Ensure API documentation is always correct and easily accessible, both for internal developers and external parties.

Possible paths ahead

  1. Annotate web server routing code and generate documentation based on annotations, e.g. using apiDoc.
  2. Write API specs on machine-readable format and generate documentation based on spec.

Annotation of routing code (1) did not seem like a tasty option for us, mainly because:

  • We already had a lot of routes defined = we’d need to change a lot of files
  • It’s still easy to miss an annotation when editing, i.e. the spec wouldn’t be correct

To instead go with (2) writing specs on a machine-readable format seemed like we could use it for even more things moving forward:

  • generate documentation
  • generate code
  • … and even convert to another machine-readable format if needed

Also, the idea of actually generating the routing code made most sense, since that would ensure that the code is always working as the API spec says. That also means that the API documentation would always be correct.

Picking an API spec format

There are a few different formats available out there, where we looked most att API Blueprint and OpenAPI (fka Swagger).

Both are established, have extensive tooling available and possibilities to build your own.

OpenAPI allows you to write specs in JSON or YAML, whereas API Blueprint had its own Markdown-like syntax.

We ended up picking OpenAPI, because it seemed to be less painful for us:

  • API Blueprint’s syntax was error prone and we failed hard when having a space too few or too many

  • JSON is already top-of-mind since we’re working a lot with Node.js and JSON as primary format in our APIs

New OpenAPI Spec Workflow

  1. Write the API spec on OpenAPI format. We use .js files for the spec to add more structural sugar than .json (e.g. to split the spec into smaller parts and `require()` them into one).
  2. Generate API docs as Markdown using a swagger-md (which we had to build, since we couldn’t find any pure Javascript library doing this). API.md is placed in the Github repository of the API, easily available for developers.
  3. Generate api.json OpenAPI spec, that can be shared with external parties and used in Swagger Editor and other tools (like the static API mentioned below).
  4. Load API spec in web server application and let swaggerize-hapi configure routing in Hapi. We map each endpoint to a function in handler-mapping.js.
const api_spec = require('./api');
const handler_mapping = require('./handler-mapping');
function routeSwaggerSpec(hapi_server) {
return hapi_server.register({
register: swaggerize,
options: {
api: api_spec,
handlers: handler_mapping,
docspath: '/',
},
});
}

Bonus feature ⭐️

A bonus from having the OpenAPI spec is that we can use it to generate a stand-alone static API server.

The static API is wired up to respond to each endpoint with a static .json fixture file, making it possible to run it as a localhost and use it as a representation of the actual web server.

This makes it possible to install the static API into other modules depending on the real API, and have them run acceptance and protocol tests without having to depend on an external resource. 👌🏻


The new OpenAPI spec workflow.

Where We Are Today

  • All API changes made to the spec and only to the spec.
  • Documentation and API spec always correct.
  • Protocol tests from all apps and internal services, running against the static API.

Migrating to OpenAPI from having all documentation in regular README.md files wasn’t effortless, but not a gigantic effort.
It took ~3–4 days to migrate an entire API (with 20+ endpoints), including moving from
Restify to Hapi.