Documentação de APIs
Neste tutorial sobre documentação de APIs iremos aprender:
- O que é uma API?
- Qual o propósito de uma documentação de API?
- Meios de documentar
- Como este processo é feito na iTFLEX
- Executando a documentação
O que é uma API?
API é a sigla para Application Programming Interface (em português, Interface de programação de aplicativo), como seu nome diz, trata-se de uma interface capaz de integrar um ou mais serviços/aplicações. Isso possibilita que aplicações que utilizam linguagens e tecnologias diferentes, possam se comunicar através de uma API.
Qual o propósito de uma documentação de API?
A documentação de uma API permite que outros desenvolvedores utilizem ela como base, para poder integrar seus sistemas. Trata-se de uma espécie de manual de como integrar o seu produto com outro, nele sempre é documentado qual o endpoint da API, os campos de requisição e respostas, quais tipos de retornos HTTP podemos esperar e exemplos de como usar a API.
A documentação deve ser sempre o mais clara e objetiva possível, não devemos nos enrolar em explicações de campos ou endpoints. Uma documentação clara e objetiva, facilita o entendimento, assim como exemplos práticos e reais.
É sempre importante, se possível, ter exemplos do consumo da API em diferentes linguagens de programação.
Sempre documentar e explicar as mensagens de erro que sua aplicação pode retornar, isso facilita ao desenvolvedor que irá utilizar sua documentação para entender como a sua API se comporta.
Meios de documentar
Para documentar sua API você pode utilizar desde uma página HTML até ferramentas que automatizam esse processo, porém, sabemos que o processo de documentação de uma API não é apenas escrever uma página em HTML. O fator interativo da documentação que permite que as funcionalidades sejam testadas no momento que o usuário visualiza a documentação é um dos maiores diferenciais, e para isso temos a nossa disposição:
Swagger
O Swagger, uma das mais antigas formas de documentação de API na web, construída com base no JSON, é o formato mais popular para APIs RESTful, além do seu como especificação de API, pode ser utilizado como um framework dependendo da linguagem que você está utilizando.
O objetivo do Swagger é permitir uma documentação que evolua junto com as APIs do seu produto de forma automática através de notações do código. O Swagger entrega à disposição do desenvolvedor todo um conjunto de ferramentas.
-
Codegen: ao ser executado, o aplicativo
swagger codegen
converte as anotações do código-fonte das APIs em documentação. -
Automaticamente: alguns servidores, como o
swagger-node-express
e oswagger-play
, podem criar, ao mesmo tempo, a documentação e as APIs. -
Manualmente: de forma totalmente livre, é possível escrever manualmente os arquivos JSON com a especificação swagger das APIs e publicá-los no seu próprio servidor ou em algum dos disponíveis, como o node.js server generator.
OpenAPI
Vindo da mesma ideia do Swagger, o OpenAPI, se trata de uma maneira de especificar sua API. É um projeto da SmartBear
, empresa responsável pelo Swagger, que foi doado para a OpenAPI Initiative
.
Possui plugins para os editores mais utilizados no mercado, para fins de automatizar a geração da documentação.
- Dispõem de um ṕlugin no vscode para auxiliar na automatização do processo de especificação.
API Blueprint
O API Blueprint é um projeto de especificação em Markdown, que em comparação com o Swagger tem uma curva de aprendizagem um pouco maior, o que pode levar o usuário que vai utilizar a fazer uma grande imersão nos seus tutoriais.
Possui um conjunto de ferramentas, que se responsabilizam por cuidar do design da documentação, do ciclo de vida da API e de testes.
RAML
O RAML é um meio de especificação que utiliza YAML com foco na clareza, precisão, consistência e legibilidade da API. Focado no auxílio para fazer o design da API.
Como este processo é feito na iTFLEX
Na iTFLEX, utilizamos o formato de especificação OpenAPI. Entretanto, não utilizamos nenhum codegen ou forma de automatização, realizamos o processo de documentação manualmente.
Para encontrar a documentação de nossas APIs, você deve ir até o diretório do projeto e na pasta /backend/docs
, aqui você irá encontrar toda a documentação da nossa aplicação FwFlex.
Neste diretório se encontram alguns arquivos que são importantes e devem sofrer manutenção, como:
types.yml
onde estão estruturas/objetos padrões que se repetem em nossas APIs. Incluímos este arquivo para não ficar duplicando o conteúdo.index.yml
onde estão algumas configurações da página das documentações renderizada._index.yml
onde estão algumas informações gerais sobre a API, como versão, licença, DNS do servidor, um descrição, etc.
Neste diretório ainda, temos outros diretórios, que se trata da divisão das APIs, seguindo um esquema de contexto, esse contexto compreende um conjunto de módulos e cada módulo um conjunto de recursos, no qual cada recurso tem suas APIs.

Dentro dos módulos, temos sempre o arquivo _index.yml
, nele estão as tags, elas servem para que nós indexamos as nossas APIs, atrelando elas a um grupo para que em tela ela seja mapeada, essa tag é definida pela cláusula name
, junto de outra cláusula description
que serve para termos um texto mais descritivo sobre o que se trata a API:
tags:
- name: "Bot - Options"
description: "API de listagem de opções de ação para o bot."
- name: "Bot - Deploy"
description: "API de realizar deploy dos projetos pelo bot."
Além deste arquivo, você deve encontrar em todo diretório de módulo um arquivo _types.yml
, nele escrevemos estruturas/objetos de retorno e resposta de API, que se repetem entre os objetos daquele módulo. Utilizamos ele para não gerar duplicidade no código, permitindo assim reutilizar uma estrutura apenas incluindo ela em outra.
Para cada recurso de um módulo, teremos dois arquivos:
- Aquele referente a documentação das URLs da API, que possui os status de retorno, escopos de permissões, etc. Este arquivo geralmente leva em seu nome, o nome do recurso, exemplo:
deploy.yml
- Aquele referente a documentação das estruturas e objetos de retorno da API. Como já mencionado anteriormente, estes arquivos possuem a palavra
_types
em seu nome, logo para o exemplo dado acima, ficaria:deploy_types.yml
Documentação da API
Neste arquivo de documentação geral de uma API, descrevemos todos os endpoints
daquele recurso, cada recurso pode ter N end-poins
, com os 4 métodos HTTP que comumente usamos: GET
, POST
, PUT
, DELETE
.
paths:
/api/bot/options:
get:
tags:
- "Bot - Options"
summary: "Listar opções de ação do Bot."
operationId: "getBotOptions"
security:
- accessToken:
- "bot.options:read"
responses:
"200":
$ref: "#/x-bot/components/responses/Options"
"401":
description: "Token não autorizado, pode ser devido a um token inválido ou a nenhum por não haver token fornecido"
post:
tags:
- "Bot - Options"
summary: "Cadastrar opção de ação do Bot."
operationId: "postBotOption"
security:
- accessToken:
- "bot.options:write"
requestBody:
content:
application/json:
schema:
$ref: "#/x-bot/components/schemas/Option"
required: true
responses:
"200":
$ref: "#/x-bot/components/responses/Option"
"400":
$ref: "#/x-bot/components/responses/OptionE400"
"401":
description: "Token não autorizado, pode ser devido a um token inválido ou a nenhum por não haver token fornecido"
/api/bot/deploy/<id>:
put:
tags:
- "Bot - Options"
summary: "Atualizar uma opção de ação do bot."
operationId: "putBotOption"
security:
- accessToken:
- "bot.options:write"
requestBody:
content:
application/json:
schema:
$ref: "#/x-bot/components/schemas/Option"
required: true
responses:
"200":
$ref: "#/x-bot/components/schemas/Option"
"401":
description: "Token não autorizado, pode ser devido a um token inválido ou a nenhum por não haver token fornecido"
"404":
description: "Recurso não encontrado com o id informado."
delete:
tags:
- "Bot - Options"
summary: "Deletar uma opção de ação do bot."
operationId: "deleteBotOption"
security:
- accessToken:
- "bot.options:write"
responses:
"200":
$ref: "#/x-bot/components/schemas/Option"
"401":
description: "Token não autorizado, pode ser devido a um token inválido ou a nenhum por não haver token fornecido"
"404":
description: "Recurso não encontrado com o id informado."
No exemplo utilizado, (você acessar no GitLab o arquivo aqui) temos um CRUD simples. Você pode ver que existem diversas palavras-chaves, vamos explicar elas aos poucos, linha a linha.
Todo arquivo de especificação começa com a palavra paths
, ela serve para indicar ao OpenAPI o início das URLs da API. Logo em seguida temos os nossos endpoints
, nesse caso o primeiro é o /api/bot/options
, seguido pelo método HTTP que iremos documentar.
Dentro do endpoint
, é possível visualizar várias informações que se repetem entre os próximos endpoints
:
tag
: Serve para indexar essa documentação ao grupo dela, que criamos no arquivo_index.yml
deste módulo.summary
: Uma breve descrição do que se trata esse API.operationId
: Ẽ um identificador único utilizado apenas pelo OpenAPI. Seu padrão costuma ser<metodo><modulo><recurso>
, em casos que temos o mesmo método HTTP para o mesmo recurso como um GET geral e um GET pelo id do item, informamos no final dooperationId
.security
: O tipo de permissão que é necessário para ter acesso a essa API. O padrão sempre é<modulo>.<recurso>:<read|write>
.responses
: São todos os possíveis retornos que se pode esperar dessa API. Obs: a palavra-chave$ref
é utilizada como uma hook, ele incorpora no arquivo conteúdo presente dentro da estrutura de outra palavra-chave. No nosso exemplo tempos"#/x-bot/components/responses/Option"
, isso está presente no arquivooptions_types.yml
que explicaremos mais adiante.
Todos estes itens se repetem dentro de cada especificação de um método para os endpoints
, porém, quando vamos especificar uma API que possui um opção de requisição, novas palavras-chaves aparecem:
requestBody
: Utilizamos para informar ao OpenAPI que ele deve renderizar um elemento para informar o corpo de requisição;content
: Informar o conteúdoapplication/json
: Utilizamos para especificar que o tipo do conteúdo a ser enviado para a API deve ser umjson
, na documentação do OpenAPI existem diversos tipos de conteúdo da requisição que podemos especificar.schema
: Aqui começamos a especificar toda a estrutura do objeto de requisiçãorequired
: Quando tornamos obrigatório o envio de um objeto na requisição.
Além desses itens, o OpenAPI fornece outras informações para aprimorar a especificação da sua API, para saber mais você pode checar a sua documentação.
Objetos de Retorno e Respotas
Para definição dos objetos que a nossa API esperar receber no corpo da requisição e a estrutura do objeto que ela irá retornar, especificamos num arquivo que tem o padrão de nomenclatura <recurso>_types.yml
, o types
em seu nome é justamente para deixar visivel já que este arquivo especifica somente as estruturas dos objetos das requisições. Exemplo:
x-virtualization:
components:
schemas:
Disk:
allOf:
- title: "Objeto Disk"
description: "Disco"
type: "object"
required:
- "size"
- "location_id"
- "name"
- "format"
properties:
id:
description: "Identificador do volume."
type: "integer"
format: "int64"
readOnly: true
example: 1
size:
description: "Tamanho do disco em GigaBytes (GB)."
type: "integer"
format: "int64"
example: 20
location_id:
description: "Identificador da localização da imagem."
type: "integer"
format: "int64"
example: 1
name:
description: "Nome do disco."
type: "string"
minLength: 1
maxLength: 255
pattern: "^[a-zA-Z0-9][a-zA-Z0-9\\.\\-_]*[a-zA-Z0-9]$"
example: "archive.iso"
format:
description: "Formato do disco"
type: "string"
enum:
- "cow"
- "qcow"
- "qcow2"
- "qed"
- "vdi"
in_use:
description: "Flag que indica se disco está vinculado à alguma VM."
type: "boolean"
readOnly: true
example: true
- $ref: "#/components/schemas/ItemDTs"
responses:
Disks:
content:
application/json:
schema:
type: "object"
properties:
volumes:
description: "Lista de discos."
type: "array"
items:
$ref: "#/x-virtualization/components/schemas/Disk"
example:
volumes:
- id: 1
size: 20
location_id: 1
name: "disk1"
format: "qcow2"
in_use: false
created_at: "2020-01-16T15:42:26.308479-03:00"
updated_at: "2020-01-16T15:42:26.308479-03:00"
- id: 2
size: 20
location_id: 2
name: "disk2"
format: "vdi"
in_use: true
created_at: "2020-01-16T15:42:26.308479-03:00"
updated_at: "2020-01-16T15:42:26.308479-03:00"
description: "Requisição realizada com sucesso."
Disk:
content:
application/json:
schema:
$ref: "#/x-webfilter/components/schemas/Disk"
example:
- id: 1
size: 20
location_id: 1
name: "disk1"
format: "qcow2"
in_use: false
created_at: "2020-01-16T15:42:26.308479-03:00"
updated_at: "2020-01-16T15:42:26.308479-03:00"
DiskE400:
content:
application/json:
schema:
type: "object"
properties:
errors:
description: "Lista de erros. O padrão das mensagens de erro
está na [documentação de erros](#section/Errors).
O nome dos exemplos dos erros segue o padrão
`<nome_campo>__<tipo_erro>`."
type: "array"
items:
$ref: "#/components/schemas/ErrorConflict"
examples:
list_fields_empty:
value:
- field: null
msg: "urls, domains, categories and file_types cannot be simultaneously empty"
type: "rule"
description: "Erro nos dados da requisição, deve ser verificado o corpo
da resposta para identificar que erro ocorreu."
No começo de cada arquivo sempre tempos uma palavra-chave que se inicia com x-<recurso>
, utilizamos ela pois o modelo no qual as especificações no OpenAPI funcionam, obrigam que tudo na sua documentação ao qual se refere a endpoints, ids de operações, nomes de estruturas, seja único, porem ao utilizar esse item, podemos burlar isso e ter um objeto com o mesmo nome porem em módulos diferentes. Um exemplo seria numa situação em que temos um objeto chamado Rule
em dois módulos diferentes, um de Firewall
e outro do Webfilter
(não se preocupe com o significado destes nomes), ao utilizar a palavra-chave x-firewall
em todo local que você for incorporar a estrutura desse objeto, o OpenAPI irá saber a especificação de qual arquivo ele irá carregar.
Seguindo a edentação, cada item para dentro é um componente, nesse caso, pode ser um pleonasmo mas dentro do nosso componente x-
, temos a palavra-chave components
, no qual estão nossas especificações dos objetos.
Aqui as especificações dos objetos estão separados em duas categorias:
schemas
: Que são as definições dos objetos, no qual informamos um nome, seus campos, o tipo dos campos, um valor de exemplo, entre outras definições mais específicas.responses
: Que é a definição de retorno de uma API, o que ela irá retornar quando der um status 200 ou outro status possível.
Os schemas
sempre devem levar o nome do objeto como ele é descrito nas entidades do backend, para seguirmos um padrão de nomenclatura. Com otype
sendo objeto, e seperado item por item os campos obrigatórios em required
.
Como foi comentado, no bloco responses
estão os possíveis retornos da API, aqui você verá que os retornos de erros seguem o padrão <NomeDoObjeto>E<NumeroDoErro>
.
Executando a documentação
Existe duas formas de acessar a documentação, pela aplicação ou subindo no seu ambiente local.
-
Para acessar pela aplicação basta você inserir
api/docs
no final do ip ou DNS do servidor. Exemplo:https://192.168.47.68:9292/api/docs
-
Já para acessar de forma local, através do terminal você deve ir até o diretório
itflex/server/backend
do projeto e executar o script./run_docs.sh
. Além de subir localmente a sua documentação, esse script também faz uma validação no conteúdo.