DEV Community

Alberto Fernandez Medina
Alberto Fernandez Medina

Posted on • Originally published at onlythepixel.com

Documenting your API with API Blueprint

This article covers how to document an API REST using API Blueprint standard providing API usage info to future clients. It can also be helpful to design the structure of future API endpoints before start its development.

Note: This is the 4th post of a series of post about Building APIs With Express. Based on my last post about Mongoose, MongoDB and Express I'll continue developing over the generated code.

OMG, a lot of time has passed since my last commit and now when I look at the API there are some endpoints that I don't remember very well since the last time I developed them. Let's fix it now that I understand most of it by documenting the API using API Blueprint syntax.

API Blueprint is a very basic standard based on MSON (Markdown Syntax for Object Notation) and due to its relative simplicity to write it could be easily maintainable along the life of an API.

Documenting right

I'm going to create a new folder in my project called docs to store all the documentation about my TODO API, and "why is this? in the same repo as your code?" may you ask, well this is because I think the docs files should be as close as possible to your code to ensure that they are updated and maintained by whom is developing the API. Also because I could use them to test the API against the documentation using some nice tools.

Let's stop chattering and start coding!

Defining the API

First I'm going to define the API main info:

/docs/main.md

FORMAT: 1A

# Another TODO

Another TODO API is that, another TODO API.
Enter fullscreen mode Exit fullscreen mode

In the first line, I'm setting the format (1A) used for the document, the name for my API and a small description. That was easy, time to define the API resources after the API general description.

API Resources

FORMAT: 1A

...

# Group Tasks

Resources related to the tasks in the API.

## Tasks Collection [/tasks]
Enter fullscreen mode Exit fullscreen mode

Note: Mind the ellipsis ... as obviate code.

Now here are a couple of keywords that will define our API schema, the first one is Group that is defining a section to categorize some resource and the other one is the [/tasks] definition at the end of the second header that is defining an endpoint. Now the actions.

Actions

...

### List All Tasks [GET]

+ Response 200 (application/json)

        [
          {
            "__v": 0,
            "updatedAt": "2017-04-09T16:15:37.066Z",
            "createdAt": "2017-04-09T16:15:37.066Z",
            "_id": "586e88217106b038d820a54e",
            "isDone": false,
            "description": "test"
          },
          {
            "__v": 0,
            "updatedAt": "2017-04-09T16:15:37.067Z",
            "createdAt": "2017-04-09T16:15:37.067Z",
            "_id": "586e88337106b038d820a54f",
            "isDone": false,
            "description": "test"
          }
        ]
Enter fullscreen mode Exit fullscreen mode

A lot of stuff happening on this lines, first there is a keyword in the header [GET] indicating the verb of the request and after that it's a response definition (they must start with +, * or -, like a markdown list item) followed by the status code 200 (mandatory) and the response Content-Type application/json (optional), and at the end an example of response body (example objects must be indented with 8 spaces or 2 tabs).

What about the POST?

...

### Create a New Task [POST]

+ Attributes
    + description: `Buy milk` (string) - Task description
    + isDone: false (boolean, required) - Done status

+ Request (application/json)

        {
          "description": "Buy milk",
          "isDone": false
        }

+ Response 201 (application/json)

        {
          "__v": 0,
          "updatedAt": "2017-04-09T16:30:42.010Z",
          "createdAt": "2017-04-09T16:30:42.010Z",
          "_id": "586e88337106b038d820a54f",
          "isDone": false,
          "description": "Buy milk"
        }
Enter fullscreen mode Exit fullscreen mode

Very similar to the GET one but this time I've also specified the Request and Attributes definition.

In Attributes there is a list of items that represent the possible properties for the request body each one with the prop name, an example value, the type, if is required and a small description.

In Request I've defined an example of a request body object.

Time to deal with URI params

URI Params

For the resources that have to be accessed by attacking an URL with params (/tasks/:id in my case) there is a way to define them:

## Task [/tasks/{taskId}]

+ Parameters

  + taskId: `586e88337106b038d820a54f` (string)

### View a Task [GET]

+ Response 200 (application/json)

        {
          "__v": 0,
          "updatedAt": "2017-04-09T16:30:42.010Z",
          "createdAt": "2017-04-09T16:30:42.010Z",
          "_id": "586e88337106b038d820a54f",
          "isDone": false,
          "description": "Buy milk"
        }
Enter fullscreen mode Exit fullscreen mode

The properties defined in the URL with braces like {taskId} will be related to the definitions with the same name in the Parameters section. The Parameters section uses the same nomenclature as Attributes.

Data Structures

It is a bit of a harsh to define in each section the same response so you can define a Data Structures section in your docs to store some basic data structures.

## Data Structures

### Task

+ _id: `586e88337106b038d820a54f` (string, required) - Task's ID
+ description: `Buy more milk` (string, required) - Task's description
+ isDone: false (boolean, required) - Done status
+ createdAt: `2017-04-09T16:30:42.010Z` (string, required) - Task's created date
+ updatedAt: `2017-04-09T16:30:42.010Z` (string, required) - Task's update date
Enter fullscreen mode Exit fullscreen mode

And then reuse them on your endpoint definitions.

### Edit a Task partially [PATCH]

+ Attributes
    + description: `Buy more milk` (string) - Task description
    + isDone: true (boolean) - Done status

+ Request (application/json)

        {
          "description": "Buy more milk"
        }

+ Response 200 (application/json)

        + Attributes (Task)
Enter fullscreen mode Exit fullscreen mode

Here in the Response definition, I have used my Attributes data structure.

That's it!

I think I've covered all the basic cases by now, you can read this Advanced Tutorial about API Blueprint and define a much more robust API.

As always you can check the code on GitHub and you can review the Another TODO API docs in Apiary

Top comments (2)

Collapse
 
bgadrian profile image
Adrian B.G.

It would be cool if devs would have the time to update the documentation too, but this is not the case in most projects. I will bookmark the project to use it only at the design phase of a new API, before creating the mockup server/clients.

I would recommend a more realistic and pragmatic approach, as your unit tests is a documentation of your code, a series of API tests (like a Postman collection) should be enough for any API. It can also be used in the Integration pipeline so you cannot "forget" to update it.

Collapse
 
albertofdzm profile image
Alberto Fernandez Medina

Thanks for the comment!

I think that documentation is needed always to ensure the health of the project, sometimes even more than tests. In my actual company, we were documenting at least the necessary things and we are losing it day by day.

The main problem, in my opinion, is that sometimes nobody reads these docs for months until someone new comes to the team or you have to reuse some of that features, and probably by then that info would be obsolete.

I agree with you that is hard to maintain documentation.

In my next article, I'll be using Dredd for test these docs against the API server ensuring by that way the info is up to date. So, at the end, this docs will be more useful ensuring even code coverage.