Juarez Lustosa
Todos os projetos

Plataforma de API pública para uma rede de serviços de caminhões

Endpoints contract-first, documentação sincronizada e investigação de performance no banco de dados de uma API REST pública.

Empresa
Decisiv
Papel
Engenheiro de Software Sênior, time de API
Período
2020 — hoje
Stack
  • Ruby on Rails
  • PostgreSQL
  • dry-rb
  • JSON:API
  • OpenAPI
  • Datadog
  • LogScale
  • AWS

O problema

A Decisiv mantém uma plataforma em que montadoras, concessionárias e frotas de caminhões gerenciam eventos de serviço: um caminhão chega à oficina, um orçamento é escrito, a frota aprova, o reparo é feito e faturado. Essas empresas têm sistemas próprios e precisavam ler e gravar esses dados sem entrar em uma aplicação web.

A plataforma já tinha uma API REST pública, mas adicionar recursos exigia coordenação entre implementação, documentação e permissões. A validação de entrada vivia em classes avulsas de “extrair e validar” sem regras compartilhadas, a documentação OpenAPI era editada à mão e descolava do código, e as permissões de um endpoint novo eram um passo manual separado e fácil de esquecer. Alguns endpoints de listagem também precisavam de trabalho de performance sob cargas maiores.

O que eu fiz

Sou um dos engenheiros responsáveis pela camada de API. Nos últimos anos minha parte tem sido: desenhar e entregar recursos novos, o trabalho de performance nos endpoints lentos, a documentação OpenAPI e os dashboards e monitores que avisam o time quando algo regride.

Como resolvi

Validação contract-first. Todo endpoint agora começa com um contrato dry-validation que declara os parâmetros, seus tipos e as regras entre campos. O contrato é escrito e testado antes de o controller existir, e o controller só roda quando o contrato passa. Regras compartilhadas (paginação, sparse fieldsets, sintaxe de filtro) ficam em macros reutilizáveis, então dois endpoints não conseguem validar a mesma coisa de jeitos diferentes.

Três mudanças coordenadas por recurso. Um recurso novo sai como três pull requests revisados juntos: a API em si, a especificação OpenAPI no repositório dela e a semente de permissões que diz à camada de autorização quais perfis podem chamar o endpoint. Sem a terceira um cliente real recebe um erro de pré-condição, então o padrão torna impossível não perceber o bug da “permissão esquecida”.

Banco primeiro na performance. Investigo endpoints lentos separando consultas repetidas de associações do custo da consulta principal. Esse trabalho inclui ler planos de execução, conferir estimativas e índices disponíveis, e comparar alternativas de consulta com dados representativos. O carregamento antecipado de associações e as mudanças na consulta principal são avaliados separadamente.

Observabilidade. Os logs de requisição carregam a aplicação OAuth, o tenant, o endpoint e o tempo, então dashboards no Datadog e no LogScale mostram uso e taxa de erro por parceiro e por endpoint. Os monitores acionam em mudanças de taxa de erro e latência, não em limites fixos.

O que foi difícil

Escopo multi-tenant. O mesmo endpoint atende frotas, concessionárias e patrocinadores, e um filtro correto para um formato de conta é errado para outro. Acertar a política exigiu ler como cada chamador se relaciona com os dados, não só quem ele é.

Distinguir um N+1 real de uma regressão de plano. Os dois aparecem como “o endpoint está lento”, e as correções não têm nada em comum. Hoje sempre pego um plano de consulta em um ambiente com dados parecidos com produção antes de mexer no código da aplicação.

O resultado

O trabalho de performance reduziu a latência dos endpoints envolvidos. Recursos novos saem com documentação e permissões na mesma release, e o checklist de revisão é o próprio padrão. Dashboards por parceiro fazem com que um problema de integração de um cliente geralmente apareça antes de ele escrever.

Onde conferir

A documentação pública para desenvolvedores está no link abaixo. O código é privado. Um artigo separado neste site usa um exemplo fictício para explicar como investigo o comportamento do planejador de consultas.