API Blueprint: Markdown é vida!

Estamos falando sobre escrever especificações de APIs há um bom tempo aqui no blog. RAML, Swagger e OpenAPI Specification já foram explorados, e com os dois últimos encontramos um ecossistema rico com ferramentas extremamente interessantes.

Há um outro simpático player no mercado, o API Blueprint, e o post de hoje é sobre essa prática ferramenta.

A menor curva de aprendizado do Oeste

Um colega de trabalho, há muito tempo atrás, me apresentou o API Blueprint. Na ótica dele, um dos aspectos mais interessantes era a escrita utilizando Markdown.

Antony Hopkins em Westworld
É um formato para máquinas? É um formato para humanos? Que diferença faz? (tvguide.com)

Sim! É verdade! Claro que utilizando o formato/extensão específico há ganhos como syntax highlighting, mas ainda assim é possível escrever a especificação de uma API somente com Markdown, o que torna a leitura do documento mais amigável, e interoperável com ferramentas como o seu editor de textos, ou o próprio Github.

Como o documento é apresentado pelo Github
Como o documento é apresentado pelo Github

Para quem já tem um README.md em seu repositório, ter um api.md não parece ser nenhum grande sacrifício. E dependendo do seu público alvo, ter a "documentação final gerada" pode ser tão simples quanto compartilhar o link da especificação no Github.

Mas o que é API Blueprint mesmo?

A documentação oficial o define da seguinte forma:

(...) is simple and accessible to everybody involved in the API lifecycle. Its syntax is concise yet expressive. With API Blueprint you can quickly design and prototype APIs to be created or document and test already deployed mission-critical APIs.

Assim como os já citados RAML e Swagger, o API Blueprint é uma linguagem de design utilizada para descrever APIs. O seu propósito é o de encorajar o diálogo e colaboração, logo, uma ferramenta mais que ideal para adoção no seu processo de API-First.

Para ter os ganhos que citei anteriormente, o API Blueprint usa um "melhoramento" do Markdown chamado de MSON (Markdown Syntax for Object Notation). É com essa notação que utilizamos a síntaxe do Markdown para descrever estruturas de dados, heranças e recursos.

Leia a especificação do MSON.

Começando

Voltando ao bom e velho exemplo do mini IMDB, vamos criar um arquivo api.md e pôr a mão na massa.

Começamos por definir qual versão do API Blueprint utilizaremos, bem como descrevendo o nome da API e seu propósito:

FORMAT: A1

# Movies API

This is an API Blueprint example describing a movies API.

O #, no Markdown, é associado a um "título de nível 1". Ou seja, o # Movies API se convertido em HTML produziria um <h1>Movies API</h1>. Nesse caso, o # produz o título da API. O # também é utilizado para agrupar recursos, mas nesse caso, ele necessita da keyword Group:

FORMAT: A1

# Movies API

This is an API Blueprint example describing a movies API.

# Group Movies

Resources related to movies in the API.

Descrevendo recursos

O próximo passo é descrever o recurso e seus endpoints. Começaremos pelo endpoint /movies. Para descrever o recurso, utilizamos o ##, já a ação é representada através de 3 hashtags (###):

(...)

## Movie collection [/movies]

### List all Movies [GET]

List movies in reverse order of publication.

- Response 200 (application/json)

Quando o recurso /movies receber uma requisição GET, ele responderá com o status code 200, e com o content-type application/json. Essa última parte é descrita através da linha + Response 200 (application/json).

Exemplo de representação do endpoint
Exemplo de representação do endpoint

Podemos também descrever como será o payload dessa resposta.

Descrevendo os dados

É possível utilizar JSON Schema para descrever o payload de requisições e respostas. Como ilustrado nesse exemplo tirado da documentação oficial:

### Create a New Question [POST]

You may create your own question using this action. It takes a JSON object
containing a question and a collection of answers in the form of choices.

- Request (application/json)

  - Body

          {
            "question": "Favourite language?"
            "choices": [
              "Swift",
              "Objective-C"
            ]
          }

  - Schema

          {
            "$schema": "http://json-schema.org/draft-04/schema#",
            "type": "object",
            "properties": {
              "question": {
                "type": "string"
              },
              "choices": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "minItems": 2
              }
            }
          }

O JSON Schema é um vocabulário poderoso para anotar e validar documentos JSON. No entanto, ele pode "destoar" do resto do seu documento.

Há uma alternativa utilizando o próprio MSON. Através da seção ## Data structure, conseguimos algo semelhante com o ilustrado acima.

(...)

## Data structures

### Movie

- id: 810b43d0-fc0d-4199-8a79-25b471c880bf (string, required)
- title: Avengers: Endgame (string, required)
- description (string)

Descrevemos a estrutura Movie, informando o seu id (string e obrigatória), title e description. Note que este último, além de não ser obrigatório, não possui nenhum exemplo informado (como os dois outro campos).

Para associar a estrutura acima com a resposta de /movies, utilizamos Attributes:

(...)

### List all Movies [GET]

List movies in reverse order of publication.

- Response 200 (application/json)

  - Attributes (array[Movie])

(...)

Com ajuda do tipo array, descrevemos o payload da resposta do endpoint.

Exemplo de representação do payload
Exemplo de representação do payload

No fim das contas, um JSON body e JSON Schema é gerado através dos atributos MSON. Por isso do bloco Schema, exibido na imagem acima.

Visite o tutorial do API Blueprint e veja como aplicar a especificação para os demais verbos HTTP.

O exemplo completo pode ser conferido aqui.

As imagens representando a especificação foram extraídas do plugin API Blueprint Viewer, para o VS Code.

Considerações finais

Na página de Tools do site oficial é possível conhecer as diferentes ferramentas à disposição, que vão desde editores até mock servers.

Nesse quesito, uma das ferramentas que me conquistou foi o Dredd, que é utilizado para validar especificação, e funciona tanto com o API Blueprint quanto com o OpenAPI. Aliás, OpenAPI/Swagger ainda são "campeões" no quesito ferramentas disponíveis.

Pela característica do Markdown, e de ser relativamente mais barato de escrever, eu tive a oportunidade de utilizar o API Blueprint da seguinte forma:

  • Propostas de adições, remoções e alterações são escritas através de API Blueprint e discutidas com os stakeholders;
  • A solução é escrita e o contrato é validado através do Dredd;
  • Mas a especificação pública é gerada através do código-fonte, com o Swagger;
  • E a partir dessa especificação é gerada a documentação final e SDKs.

A facilidade de escrita de documentos API Blueprint faz dele uma ótima opção e um player mais que interessante no cenário de specs REST. Um terreno ainda dominado pelo Swagger...

Até a próxima.