If you open an API to the customers, you need to document it and give concrete examples. At some point, we have decided that documenting an API using Google Doc was the best way to do this (do not laugh, we had our reasons).
The document was full of examples following the same pattern: "title" - "description" - "curl snippet". To the reader the document looked like this
Get information X
You can get information X from our API by using
1 | curl -H 'Authorization Token: <YOUR TOKEN>' 'https://domain/api/v2/x?foo=bar' |
With the API growing and sometimes changing, keeping the document up to date became a problem. We were also worried that a wrong curl snippet would really land an egg on our face.
Unit testing curl snippets
First thing we need to do was to make sure our curl commands were indeed still working. We placed all of them into JS file (in reality it was a TypeScript file) and then wrote unit tests that exercised some of the snippets (other snippets were combinations of individual steps which we exercised using regular end to end API tests).
1 | export const getX = { |
Notice how the command object looks just like our documentation! Next we need to test it. The test runs during our end to end tests against a deployed service on an actual domain, and we have the token passed via environment variables. Thus at test time, we convert the general snippet into actual call
1 | // at runtime, process.env values 'TOKEN' and 'HOST' will |
We would execute the formed command, but we do not want to use the shell for this - it is less
than secure, even in the CI environment. Thus we need to split a complex command into the
program name (curl
in this case) and the list of string arguments. We used
snailescape.js to do this.
1 | const SnailEscape = require('snailescape.js') |
Next we execute the command, for simplicity using execa
1 | const commandParts = parser.parse(formCommand(getX.command)) |
And that was it - now we can just parse the standard output and confirm the expected values.
Documentation
Once we got all or some curl commands tested, we replaced the manual Google doc with generated documentation. So we grabbed the command objects and just converted them to Markdown text.
1 | import {examples} from './commands' |
When running we piped the output to a markdown file for simplicity. The generated file looked great and could be hosted anywhere, or even rendered as HTML later.
Final thoughts
Making a curl example into a full code "citizen" helped us avoid the docs diverging from the reality, and forced a developer to think right away how to test and document a new feature. In the future we can also generate dynamic custom code snippets shown to a particular client (where we know the token and the custom domain name).
For a situation where we could not use Swagger or similar API generation and documentation tool, we came up with a good solution in our opinion.