A criação de uma API é uma parte fundamental no escopo de qualquer serviço online. Mesmo quando pensamos em APIs privadas, elas viraram o feijão com arroz da arquitetura básica de qualquer aplicação.
Os benefícios de construir suas aplicações pensando na camada de API como um aspecto importante vão além de qualidades técnicas. APIs se tornaram alavancas importantes para o negócio de uma empresa.
Vamos entender formas diferentes de conduzir a construção da API de sua aplicação, destacando prós e contras de cada modelo e quais cenários se beneficiam deles. Bora lá!
O que é uma API?
A troca de dados entre aplicações usando algum padrão de comunicação possibilita a “Interface de Programação de Aplicação”, do inglês Application Programming Interface (ou API).
APIs geralmente seguem uma arquitetura cliente/servidor onde o cliente faz requisições e o servidor emite respostas após algum tipo de processamento. Existem exceções, mas em geral, essa é a regra.
Existem diversos padrões de mercado adotados para definir o modelo de comunicação usado em APIs: SOAP, RPC, GraphQL, REST, entre outros menos conhecidos.
Whatsapp, Google Maps, Steam, Binance, Github e Mercado Livre são exemplos do que as APIs possibilitam. Com elas, construímos arquiteturas distribuídas e robustas, frequentemente escaláveis e documentadas.
De acordo com o relatório State of Internet Reports da Akamai, cerca de 83% do tráfego de toda internet é gerado por serviços que possuem APIs como elementos centrais para o seu funcionamento 🤯.
O que é uma API Rest?
Diferentes modelos de API foram criados, mas o padrão Representational State Transfer (REST) foi o que mais se destacou. Em português pode ser traduzido como Transferência de Estado Representacional.
Fruto da dissertação de um estudante chamado Roy Fielding, este modelo ganhou espaço se tornando o padrão adotado pela maioria das aplicações e frameworks web.
E qual a razão deste de modelo ser tão famoso?
Ele define uma série de padrões que se tornaram importantes para a industria de desenvolvimento de sistemas distribuídos.
Utilizando os fundamentos do protocolo HTTP, com o REST criamos aplicações cliente/servidor usando interfaces bem definidas, com mensagens em um formato auto-descritivo, focando em recursos importantes para o negócio através dos verbos HTTP.
APIs REST são um tema grande por si só que irei escrever em um post a parte. Por ora, precisamos entender que ele existe e caso não haja nenhum motivo especial no seu projeto, esse deve ser o modelo a ser seguido.
Abordagens diferentes ao construir APIs
Existem duas estratégias principais ao desenvolver APIs:
- Code First: foca em acelerar a criação da API indo direto para o código, definindo o contrato dela conforme a aplicação for sendo criada;
- Design First: começa definindo o contrato da API e buscando feedbacks dos principais envolvidos para só então iniciar a fase de codificação;
Code First
Se colocarmos em perspectiva histórica, a abordagem Code First é a mais tradicional. Desta forma os desenvolvedores definem o contrato da API ao mesmo tempo que criam as rotas da aplicação.
Benefícios
Trabalhar no modelo Code First significa que você irá começar o projeto codificando antes, o que pode acelerar o processo de entrega nas seguintes situações:
- APIs simples: quando você precisa codificar uma API de baixa complexidade e os requisitos de negócio já estão bem definidos;
- Time familiarizado com a natureza do problema e donos dos clients da API: se você conhece os requisitos de negócio e desenvolve os clientes da API, obrigar uma etapa de design e alinhamento pode não ter um retorno claro.
Mesmo nesse cenário, documentar a sua API ainda se torna um passo importante – e algumas vezes esquecido. Isso significa que mesmo que o seu time tenha domínio das rotas, ter uma documentação da API acelera o processo de onboarding de novos desenvolvedores.
Atualmente, gerar documentações dinâmicas a partir do código (ex: via Swagger) são a preferência de times que optam por esse caminho.
Problemas com essa abordagem
Essa estratégia é tentadora pois promete um desenvolvimento rápido, mas esconde um perigo: tomar decisões durante muito tempo sem alinhar com os consumidores da API.
Passar semanas “imaginando” a melhor API e postergar os feedbacks de quem realmente vai consumi-la atrasa a identificação de mudanças importantes. Uma vez que sejam detectadas tardiamente, essas mudanças trazem custos significativos ao exigir mudanças na estrutura da API.
Além deste problema, temos uma questão relacionada a documentação da API após a fase da codificação.
Em geral, dizer “depois vamos documentar a API” significa que dificilmente a API será BEM documentada. E isso é um problema ainda maior quando existem times externos consumindo a API, pois o custo de alinhamentos de comunicação geralmente é maior.
Codificar a sua API, colocar em testes/produção e desenvolver os clients dela certamente consumirá um esforço considerável do seu time. Após essa etapa, documentar a API já não traz mais o mesmo benefício, pois a documentação não teve tempo de ser lapidada como parte do processo.
E o problema ainda é maior quando usada uma documentação estática como em um README ou Wiki, pois tende a rapidamente se tornar obsoleta e desatualizada em relação ao código.
A WeWork, empresa de coworkings espalhados pelo mundo, em 2016 possuía cerca de 50 programadores que construíram cerca de 30 APIs sem nenhuma documentação. Desta forma, após algum tempo os desenvolvedores decidiram criar novas versões dos endpoints porque ninguém conseguia lembrar o que cada rota fazia.
API First
Diferentemente do Code First, aqui a definição da API se torna um passo fundamental a ser dado antes do código ser escrito.
Isto é, definir o contrato da API é crítico para o negócio e quanto antes os envolvidos tiverem acesso a ele, mais rapidamente ajustes podem ser feitos.
Com toda a certeza, começar com a definição do contrato garante consistência, reutilização e interoperabilidade entre todos que precisem usar a API.
Benefícios
Ter a certeza que existe uma fonte de verdade única sobre o que a API faz resolve muitos problemas de comunicação. Assim, os desenvolvedores da API e clientes consumidores podem avançar cada um na sua frente de trabalho.
Podemos listar duas grandes vantagens dessa abordagem:
- Redução de custos de alterações na API: mudar a API antes de codifica-la será mais barato do que realizar alterações depois de quase tudo pronto;
- Maior capacidade de paralelismo: os times podem iniciar a codificação das suas apps, tendo a confiança de que todos avançarão respeitando um contrato em comum;
Problemas com essa abordagem
Modelos que digam “planeje tudo antes, execute depois” partem do otimismo de conseguirmos identificar todos os casos de uso importantes na fase de planejamento.
Entretanto, o racional desse modelo me faz lembrar dos tempos do Waterfall: “se planejarmos tudo antes, podemos ir para a etapa de desenvolvimento sem surpresas” 🤞.
A minha maior percepção de problema aqui é que existe uma “fase de design”, que inicia e termina antes da implementação da sua API. Portanto, segundo o Design First, você não precisará revisitar as suas decisões no momento da codificação.
O Design First é uma evolução na criação de APIs, mas não descarta a possibilidade de querermos mudar seu contrato após a fase inicial.
Construindo APIs de forma iterativa e incremental
Talvez o movimento ágil já tenha respondido esse problema: ciclos de feedback contínuos, possibilitando evoluções por etapas a cada recurso implementado ou versão liberada da aplicação.
Sem dúvida, é natural que APIs necessitem de evoluções com o tempo, sejam por necessidades técnicas ou devido as necessidades do negócio precisarem mudar. Assim, buscar mudanças e feedbacks dos envolvidos deve ser frequente – não somente decorrente da “fase de design”.
Um caminho híbrido entre os dois modelos citados anteriormente pode ser a saída para esse problema. Usando alguma solução de documentação dinâmica, podemos gerar um mock da API o mais rápido possível e assim colher feedbacks dos endpoints no mundo real.
O mesmo documento criado para definir a API acaba se transformando um gerador de recursos de forma que permita validar na prática o funcionamento dela.
Assim, com um esboço do contrato definido, mesmo que parcial, podemos ter algo funcional para apresentar e buscar feedbacks de mudanças e novas funcionalidades.
Com os feedbacks, podemos retroalimentar o processo, gerando uma nova rodada de deploys, novos feedbacks e por fim, novas mudanças.
Como boa parte do mercado precisa criar APIs, tivemos uma explosão de ferramentas que ajudam a desenvolve-las e documenta-las.
A lista é grande, mas existe a geração automágica de servidores, clients, integração com Gateways, mocks e até mesmo código para os mais corajosos entusiasmados. Deixarei algumas sugestões de ferramentas úteis no final do post.
Na próxima sessão abordarei algumas dessas ferramentas e padrões de documentação.
OpenAPI, Swagger e API Blueprint: qual o papel deles?
Como mencionado, ferramentas para documentar e compartilhar a especificação da sua API surgiram da necessidade comum das empresas e desenvolvedores.
Certamente as ferramentas mais comuns são:
OpenAPI e Swagger
Baseado em YAML, o OpenAPI surgiu como uma evolução da especificação utilizada pelo Swagger.
No entanto, existe uma confusão comum aqui: qual a diferença entre OpenAPI e Swagger?
O OpenAPI é a especificação deste modelo de documentação e Swagger é a solução de software que implementa essa especificação, através de ferramentas para trabalhar com ela.
Por exemplo, temos a seguinte documentação seguindo a especificação do OpenAPI:
swagger: '2.0'
info:
version: 1.0.0
title: Codigo35
description: |
#### Exemplo de documentação Swagger.
schemes:
- http
host: codigo35.com
basePath: /api
paths:
/:
get:
responses:
200:
description: Retorna Ola mundo GET
post:
responses:
200:
description: Retorna Ola mundo POST
parameters:
- name: codigo
in: formData
description: parametro de test
type: string
/test-path/{id}:
parameters:
- name: id
in: path
description: ID
type: string
required: true
get:
responses:
200:
description: Retorna o ID solicitado
API Blueprint
Utilizando Markdown como sintaxe, o API Blueprint é uma solução cuja a legibilidade tenta ser mais simples que o YAML usado no OpenAPI.
Só para ilustrar, segue abaixo um exemplo de documentação :
FORMAT: 1A
HOST: https://codigo25.com/
# API Codigo35
Esta é uma API simples desmontrando a integração com o API Blueprint.
## Coleção de rotas de teste [/]
### Hello World via GET [GET]
+ Response 200 (application/json)
{
"mensagem": "Hello, World!"
}
### Hello World via POST [POST]
Aqui você pode adicionar alguma descrição da sua rota.
+ Request (application/json)
{
"mensagem": "Hello, Codigo35"
}
+ Response 200 (application/json)
{
"mensagem": "Hello, World!"
}
Qual das opções usar?
Salvo você ter alguma razão específica para usar o API Blueprint, a recomendação é usar OpenAPI + Swagger. O motivo é simples: ele é o formato adotado pela esmagadora maioria do mercado até então.
Gerando documentação a partir do código-fonte
Vou deixar abaixo alguns componentes open source que permitem a você integrar o código da sua aplicação ao formato Swagger.
Todavia, esta lista não é de forma alguma extensiva e caso você queira encontrar mais opções, basta ir ao Github e procurar pelos termos Swagger + <linguagem ou framework>:
Linguagem | Framework | Github |
---|---|---|
C# | .net | https://github.com/domaindrivendev/Swashbuckle.AspNetCore |
C# | .net | https://github.com/RicoSuter/NSwag |
Ruby | Rails | https://github.com/rswag/rswag |
Python | Django | https://github.com/marcgibbons/django-rest-swagger |
JS (Node) | Express | https://github.com/scottie1984/swagger-ui-express |
Go | Diversas | https://github.com/swaggo/swag |
Java | Spring | https://github.com/springfox/springfox |
PHP | Laravel | https://github.com/DarkaOnLine/L5-Swagger |
Elixir | Phoenix | https://github.com/xerions/phoenix_swagger |
Exemplo de API documentada
Criei um projeto simples utilizando a linguagem Go com a framework Echo. Também adicionei a lib Swaggo para geração automática da documentação Swagger. O código abaixo encontra-se neste repositório.
A API possui somente duas rotas, como pode ser visto no código abaixo:
e := echo.New()
e.GET("/", helloWorldHandler)
e.POST("/status", statusCodeHandler)
e.Logger.Fatal(e.Start(":1323"))
A saber, ao integrar com o Swaggo os seguintes passos são importantes:
- Adicionar a dependência da lib
- Fazer o
swag init
para gerar o diretório de documentação - Adicionar a integração do Swaggo com a framework da sua escolha. No caso do exemplo, utilizei a integração com o Echo
- Colocar os imports da documentação gerada e declarar a rota por onde ela poderá ser ser acessada.
- Adicionar as rotas no router do projeto.
O Swaggo te permite gerar documentação via Swagger com comentários de função do próprio Go. Só para exemplificar, veja abaixo como ficou a documentação das rotas:
HelloWorldHandler:
// HelloWorldHandler godoc
// @Summary retorna um simples "Hello, World"
// @Description endpoint para exemplo de uma chamada GET
// @Tags codigo35
// @Success 200 {string} string "Hello, World!"
// @Router / [get]
func helloWorldHandler(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
}
StatusCodeHandler:
// StatusCodeHandler godoc
// @Summary retorna um status code recebido
// @Description ao receber um status code via POST (JSON), retorna o valor recebido
// @Tags codigo35
// @Success 200 {object} StatusCodeHandlerPayload
// @Failure 400 {string} string "error description"
// @Router /status [post]
func statusCodeHandler(c echo.Context) error {
payload := new(StatusCodeHandlerPayload)
if err := c.Bind(payload); err != nil {
return c.String(http.StatusBadRequest, err.Error())
}
return c.String(http.StatusOK, fmt.Sprintf("Status Code: %d", payload.Code))
}
type StatusCodeHandlerPayload struct {
Code int `json:"code"`
}
Por fim, uma vez adicionada as docs basta rodar um swag init na raíz do projeto. O Swaggo irá atualizar a documentação e voilà!, habemus Swagger:
Conclusão
Ainda que os extremos Code First vs. API First tentem traçar estratégias claras ao criar APIs, sabemos que o mundo real é mais complexo do que o proposto por eles.
Os ciclos de feedback / mudanças precisam ser bem-vindos no processo do seu time e desse modo entrar na cultura de entrega de valor.
Como você e o seu time trabalham ao construir uma API? Quão rapidamente conseguem absorver e comunicar mudanças ao seus clientes? Qual é a experiência do desenvolvedor (DX) ao integrar com as suas APIs? Nem sempre existem respostas prontas para esses dilemas.
Por fim, indiferente do modelo que você vai seguir, garanta que um contrato seja definido, compartilhado, validado, testado e que exista alguma estratégia clara para a sua evolução.
Referencias
- O que é uma API? – Guia de APIs para iniciantes – AWS
- API-First, API Design-First, or Code-First: Which Should You Choose
- Design First or Code First: What’s the Best Approach to API Development?
- API Design-First vs Code First
- The False Dichotomy of Design-First and Code-First API Development
- The Importance of APIs for Business | GlowTouch
Ferramentas Úteis
- Swagger e OpenAPI
- API Blueprint
- Apiary – Plataforma para desenvolver e documentar APIs
- Swagger API Editor – ambiente para desenvolver APIs Swagger
- SwaggerInspector – testar e documentar APIs Swagger (pago)
- Swagger Codegen – Gerador automático de código para integrar com apis Swagger
- Prism – gere mock servers usando um arquivo de especificação baseado no OpenAPI
- Lista de ferramentas que integram com OpenAPI
Curtiu o post? Informe o seu email no campo abaixo para que eu te avise quando novos conteúdos forem postados!