Web Development

Documenting APIs using ApiDoc.js

June 2nd, 2016 | By Caio Ribeiro Pereira | 5 min read

Learn how to write and generate elegant API documentation.

Introduction to ApiDoc.js

It is a good practice to provide detailed documentation about how the client applications can connect and consume the data from an API. The coolest thing is that we will use a simple tool that generates documentation through the code’s comments.

ApiDoc.js is a Node.js CLI module to generate the documentation.

You can install it as a global module to enable the new command apidoc into your terminal, so run this command:

npm install apidoc - g


Building an API

Obs.: In our example, we are going to use the Express web framework to build an API and to simplify things we won’t write any business rules in the routes, we’ll only create all empty routes to be able to write their necessary documentation.

So first, let’s create the task-api project and install the express module:

mkdir task - api
cd task - api
npm init
npm install express--save


To build our API code, let’s create the index.js:

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

// Serving static files from "public" folder
app.use(express.static('public'));

app.get('/tasks', function(req, res) {
    // business logic for list all tasks...
});
app.get('/tasks/:id', function(req, res) {
    // business logic for find a task...
});
app.post('/tasks', function(req, res) {
    // business logic for create a task...
});
app.put('/tasks/:id', function(req, res) {
    // business logic for update a task...
});
app.delete('/tasks/:id', function(req, res) {
    // business logic for delete a task...
});
app.listen(3000, function() {
    console.log('Task api up and running...');
});


The app.use(express.static('public')) middleware will enable a static server for the public folder, this directory will be used to put all the generated documentation’s file.

Documenting all API routes

Well, now we can write the documentation of our API. In order to do it, you just need to use some comments params provided by apidoc, you can see all params.

To start our documentation process, first, you need to create a descriptor file called apidoc.json in the root folder with these attributes:

{
    "name": "Task API documentation",
    "version": "1.0.0",
    "description": "API task list manager",
    "template": {
        "forceLanguage": "en"
    }
}

The template.forceLanguage disables the browser language detection, in this case, it will force the English language.

Now, let’s start the documentation process, by editing the index.js, route by route, the first will be the app.get('/tasks') function, and in this route, we’re gonna use the following params:

  • @api: HTTP method, the path address, and the route’s title;

  • @apiGroup: route group name;

  • @apiSuccess: describes the fields and their data types for a successful response;

  • @apiSuccessExample: shows an output sample about a successful response.

  • @apiErrorExample: shows an output sample about a failed response.


Have a look:

/**
 * @api {get} /tasks List all tasks
 * @apiGroup Tasks
 * @apiSuccess {Object[]} tasks Task's list
 * @apiSuccess {Number} tasks.id Task id
 * @apiSuccess {String} tasks.title Task title
 * @apiSuccess {Boolean} tasks.done Task is done?
 * @apiSuccess {Date} tasks.updated_at Update's date
 * @apiSuccess {Date} tasks.created_at Register's date
 * @apiSuccessExample {json} Success
 *    HTTP/1.1 200 OK
 *    [{
 *      "id": 1,
 *      "title": "Study",
 *      "done": false
 *      "updated_at": "2016-02-10T15:46:51.778Z",
 *      "created_at": "2016-02-10T15:46:51.778Z"
 *    }]
 * @apiErrorExample {json} List error
 *    HTTP/1.1 500 Internal Server Error
 */
app.get('/tasks', function(req, res) {
    // business logic for listing all tasks...
});


The next route, the app.get('/tasks/:id'), will use all params from the previous one and one more param:

  • @apiParam: describes the fields and their data types for a path parameter;

/**
 * @api {get} /tasks/:id Find a task
 * @apiGroup Tasks
 * @apiParam {id} id Task id
 * @apiSuccess {Number} id Task id
 * @apiSuccess {String} title Task title
 * @apiSuccess {Boolean} done Task is done?
 * @apiSuccess {Date} updated_at Update's date
 * @apiSuccess {Date} created_at Register's date
 * @apiSuccessExample {json} Success
 *    HTTP/1.1 200 OK
 *    {
 *      "id": 1,
 *      "title": "Study",
 *      "done": false
 *      "updated_at": "2016-02-10T15:46:51.778Z",
 *      "created_at": "2016-02-10T15:46:51.778Z"
 *    }
 * @apiErrorExample {json} Task not found
 *    HTTP/1.1 404 Not Found
 * @apiErrorExample {json} Find error
 *    HTTP/1.1 500 Internal Server Error
 */
app.get('/tasks/:id', function(req, res) {
    // business logic for finding a task...
});


In the app.post('/tasks'), it will be used the @apiParam and @apiParamExample, explain how to send data via a body request, and the @apiSuccess {Boolean} done=false Task is done? is different from the others, because the done=false means default values for a field, in this case, the done field.

/**
 * @api {post} /tasks Register a new task
 * @apiGroup Tasks
 * @apiParam {String} title Task title
 * @apiParamExample {json} Input
 *    {
 *      "title": "Study"
 *    }
 * @apiSuccess {Number} id Task id
 * @apiSuccess {String} title Task title
 * @apiSuccess {Boolean} done=false Task is done?
 * @apiSuccess {Date} updated_at Update date
 * @apiSuccess {Date} created_at Register date
 * @apiSuccessExample {json} Success
 *    HTTP/1.1 200 OK
 *    {
 *      "id": 1,
 *      "title": "Study",
 *      "done": false,
 *      "updated_at": "2016-02-10T15:46:51.778Z",
 *      "created_at": "2016-02-10T15:46:51.778Z"
 *    }
 * @apiErrorExample {json} Register error
 *    HTTP/1.1 500 Internal Server Error
 */
app.post('/tasks', function(req, res) {
    // business logic for creating a task...
});


To write the app.put('/tasks/:id') and app.delete('/tasks/:id') route’s documentation, there is no secret and no new params to explain, so take a look at how both will be written:

/**
 * @api {put} /tasks/:id Update a task
 * @apiGroup Tasks
 * @apiParam {id} id Task id
 * @apiParam {String} title Task title
 * @apiParam {Boolean} done Task is done?
 * @apiParamExample {json} Input
 *    {
 *      "title": "Work",
 *      "done": true
 *    }
 * @apiSuccessExample {json} Success
 *    HTTP/1.1 204 No Content
 * @apiErrorExample {json} Update error
 *    HTTP/1.1 500 Internal Server Error
 */
app.put('/tasks/:id', function(req, res) {
    // business logic for update a task
});

/**
 * @api {delete} /tasks/:id Remove a task
 * @apiGroup Tasks
 * @apiParam {id} id Task id
 * @apiSuccessExample {json} Success
 *    HTTP/1.1 204 No Content
 * @apiErrorExample {json} Delete error
 *    HTTP/1.1 500 Internal Server Error
 */
app.delete('/tasks/:id', function(req, res) {
    // business logic for deleting a task
});


Let’s generate the docs! To do it, just run these commands below:

apidoc - e "(node_modules|public)" - o public / apidoc
node index.js


The apidoc command will filter for all files, except from the folders node_modules and public, because it was using the flag -e "(node_modules|public)" to ignore these directories, and all generated files will be into public/apidoc folder. After running these commands you will be able to access the address: http://localhost:3000/apidoc.

This time, we have a complete documentation page that describes step-by-step how to create a client application to consume data from the API. Take a look at the image below:

api-documented

Conclusion

Now you have a well-documented API and this will allow other developers to create client-side applications using the API through the rules of the API documentation.

Before deploying your commercial or enterprise JavaScript apps to production, make sure you are protecting their code against reverse-engineering, abuse, and tampering with Jscrambler.

Start your free trial today!

Jscrambler

The leader in client-side Web security. With Jscrambler, JavaScript applications become self-defensive and capable of detecting and blocking client-side attacks like Magecart.

View All Articles

Must read next

Web Development

Testing APIs with Mocha

Creating automated tests is something highly recommended. In this chapter, we will focus only on the integration tests.

May 19, 2016 | By Caio Ribeiro Pereira | 6 min read

Web Security

Build a GraphQL API with Node

Get started with GraphQL by building an API server with Node.js and Express which can be used to create, read, update and delete contacts from an SQLite DB.

May 24, 2019 | By Ahmed Bouchefra | 6 min read

Section Divider