Api

Como construir uma API

O desenvolvimento de APIs é fundamental em qualquer serviço online. Uma boa API expõe sua aplicação ao mundo, criando inúmeras possibilidades.

Background Image

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 permitem que duas aplicações conversem entre si.
APIs permitem que duas aplicações conversem entre si.

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

Estratégias de construição de uma API
Diferentes fluxos no desenvolvimento de uma API

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

Code First
Modelo onde quem reina é o desenvolvimento do código da API

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

Expectativa vs. Realidade ao construir  uma API
Expectativa vs. Realidade

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

Design First
Modelo onde o desenvolvimento só inicia quando todos os alinhamentos tenham sido feitos.

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:

  1. 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;

  2. 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”.

Modelo Iterativo e Incremental
Modelo onde todas as etapas retroalimentam as iterações do desenvolvimento

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.

Google Trends com buscas dos termos "API Blueprint" vs. "Open API"
Google Trends comparando buscas do API Blueprint (azul) com o Open API (vermelho)

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>:

LinguagemFrameworkGithub
C#.nethttps://github.com/domaindrivendev/Swashbuckle.AspNetCore
C#.nethttps://github.com/RicoSuter/NSwag
RubyRailshttps://github.com/rswag/rswag
PythonDjangohttps://github.com/marcgibbons/django-rest-swagger
JS (Node)Expresshttps://github.com/scottie1984/swagger-ui-express
GoDiversashttps://github.com/swaggo/swag
JavaSpringhttps://github.com/springfox/springfox
PHPLaravelhttps://github.com/DarkaOnLine/L5-Swagger
ElixirPhoenixhttps://github.com/xerions/phoenix_swagger
Componentes open source para diversas linguagens e frameworks web.

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:

  1. Adicionar a dependência da lib
  2. Fazer o swag init para gerar o diretório de documentação
  3. Adicionar a integração do Swaggo com a framework da sua escolha. No caso do exemplo, utilizei a integração com o Echo
  4. Colocar os imports da documentação gerada e declarar a rota por onde ela poderá ser ser acessada.
  5. 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

Ferramentas Úteis


Curtiu o post? Informe o seu email no campo abaixo para que eu te avise quando novos conteúdos forem postados!