Auto-descriptive REST API
SOAP has many drawbacks, but powerful strengths also. One of them is WDSL, this specification that allows to describe what’s inside a Web Service: API endpoints, expected parameters, response body, error cases…
When building large systems containing dozens of different Web Services, the need of those kind of API descriptions is crucial, either for people and machines.
But in 2012, we had barely no mean to programmatically describe REST APIs. As REST is just a collection of principles and good practices and not a specification, the need of description was even greater: some web services took parameter in URI, some in HTTP headers, query parameter or a combination of all three, some used POST verb for creation and other used PUT…
That’s excatly the purpose of Swagger, a format to describe endpoints of an HTTP WebService.
Swagger uses JSON and JSON Schema to describe various endpoints, their parameters, result and errors. It does not impose API to follow any rules (it does provide some hints regarding errors or security tokens representation), unlike JSON-api. The JSON descriptor can be hard-coded or dynamically generated, and is published side by side with the HTTP endpoints.
A collection of tools use this descriptor:
- A visualization UI, that provides human-friendly information on APIs, and even allows to forge HTTP requests
- A descriptor editor, to allow non-technical people editing (and describing) the descriptor itself, without writing JSON
Reconcile code and descriptor
We choose to use Swagger at Worldline, notably for SmartData project APIs.
At this time, a small number of Node.js libraries allows to handle the Swagger descriptor, but they all had a huge drawback:
Code and descriptor was unrelated
Therefore, when a developer changes something in the code, if he forget to update the descriptor, you got the exact opposite of what you expected from Swagger.
Lack of documentation is better than a bad documentation
Some libraries already had this idea, but from a code point of view, that is generating the descriptor from code.
Our idea was the opposite: generate the code from the descriptor, to benefit from the power of Swagger editors. As we were using Express framework for our Node.js Web Services, we create a middleware able to read a valid swagger descriptor and to generate Express routes.
The Swagger descriptor can be split into parts, reflecting code organization and responsabilities. And the actual functions invoked when an Http call is received are still traditionnal Express middlewares.
The only “particular” adaptation we made to Swagger descriptor was the
nickname attribute to specify the
invoked function name that must be exported by controllers:
swagger.generator() will attach the exposed function to an Express route, declaring path, Http method, headers…
to match was is specified in Swagger descriptor
In addition to the route declaration, another middleware (
swagger.validator()) is provided to validate incoming data against Swagger descriptor.
Headers, path parameters, query parameters and incoming bodies are analyze with json-gate, a JSON-schema library,
and a casted version of parameters is attached to requesst (
req.input), to decouple controller’s code from the actual parameter location (header/query/path/body) that may change with API version.
At last, a generic error middleware can be used to format reported error in a Swagger-compliant Json response.
Swagger-jack is listed in the Swagger modules list, but as we did not put effort on it since 2013, it’s stuck on the specification previous version.
It has been overcome by the excellent Paypal’s swaggerize-express, which also promotes the idea of “Design driven”.
Code can be found on github.