DEV Community

Cover image for Como Projetar e Desenvolver APIs de Forma Git-Nativa?
Lucas
Lucas

Posted on • Originally published at apidog.com

Como Projetar e Desenvolver APIs de Forma Git-Nativa?

A maioria das equipes de API trata o contrato como algo secundário: escreve o código, gera uma especificação e depois tenta manter os dois sincronizados. No design de API git-native, a ordem muda: o contrato da API vira código-fonte, fica versionado no Git e passa por revisão como qualquer outra alteração do sistema.

Experimente o Apidog hoje

Este guia mostra como aplicar essa disciplina na prática: criar contratos em branches, revisar mudanças em pull requests e transformar uma especificação aprovada em mocks, testes, clientes e documentação. O objetivo é simples: fazer com que o histórico do Git seja também o histórico da sua API.

Se você já conhece ferramentas spec-first e quer uma visão mais orientada a produto, leia o artigo complementar sobre o fluxo de trabalho de API git-native. Aqui, o foco é implementação.

O que “git-native” significa para APIs

Git-native significa que a definição da API vive no repositório como texto simples: um arquivo .yaml ou .json ao lado do código, rastreado pelo mesmo controle de versão usado pela equipe.

Em vez de manter o contrato preso a uma plataforma em nuvem, o arquivo em main passa a ser a fonte da verdade. Qualquer interface visual, mock server, documentação ou cliente gerado é apenas uma representação desse arquivo.

Uma configuração git-native precisa de três propriedades:

  1. A especificação fica em um arquivo versionado no repositório.
  2. As alterações passam por branch, commit, pull request e merge.
  3. Mocks, testes, clientes e documentação são gerados a partir do arquivo confirmado.

Com isso, você ganha histórico, git blame, rollback e revisão de design para a superfície da API.

Por que projetar APIs no Git

Você já usa Git para proteger o código. O contrato da API deve receber o mesmo tratamento.

Histórico

Quando alguém pergunta “quando adicionamos o parâmetro cursor?”, o comando abaixo responde:

git log -p -- api/openapi.yaml
Enter fullscreen mode Exit fullscreen mode

Você vê o commit, a data, o autor e a mensagem que justificou a mudança.

Blame

Para descobrir quem alterou um campo específico:

git blame api/openapi.yaml
Enter fullscreen mode Exit fullscreen mode

Isso conecta uma linha da especificação ao PR original e à discussão de revisão.

Rollback

Se uma alteração de contrato foi ruim, reverta o merge:

git revert <merge_commit_sha>
Enter fullscreen mode Exit fullscreen mode

Depois disso, codegen, mocks e documentação podem ser regenerados a partir da versão revertida.

Revisão

Um pull request é o melhor lugar para discutir uma API antes de implementá-la. Revisores podem comentar diretamente na linha que adiciona um campo obrigatório, remove um enum ou muda um status code.

Essa é a base de um fluxo de trabalho de especificação de API baseado em Git: uma única fonte de verdade para frontend, backend, QA e documentação.

Ciclo de design de API git-native

O ciclo prático é:

  1. Criar uma branch.
  2. Alterar o contrato.
  3. Fazer commit.
  4. Abrir um pull request.
  5. Revisar e fazer merge.
  6. Implementar usando a especificação aprovada.

Exemplo: adicionar um endpoint para listar faturas de um usuário.

git checkout -b feat/api-invoices-list
Enter fullscreen mode Exit fullscreen mode

Edite o arquivo OpenAPI:

# api/openapi.yaml
paths:
  /users/{userId}/invoices:
    get:
      operationId: listUserInvoices
      summary: List invoices for a user
      parameters:
        - name: userId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum: [draft, open, paid, void]
      responses:
        "200":
          description: A page of invoices
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceList"
        "404":
          description: User not found
Enter fullscreen mode Exit fullscreen mode

Faça um commit pequeno e específico:

git add api/openapi.yaml
git commit -m "Add GET /users/{userId}/invoices contract"
Enter fullscreen mode Exit fullscreen mode

Abra o PR. O diff mostra exatamente o que mudou: caminho, operação, parâmetros e respostas.

Antes de qualquer handler existir, a equipe pode revisar:

  • O nome do endpoint.
  • O operationId.
  • Os valores do enum.
  • O uso de 404.
  • A necessidade de paginação.
  • O formato da resposta.

Depois do merge, a implementação fica limitada ao contrato aprovado. Essa é a lógica do desenvolvimento de API spec-first: o acordo vem antes do código.

Estratégia de branching para contratos de API

Use uma branch por unidade lógica de mudança. Evite PRs com dezenas de endpoints.

Tipo de alteração Prefixo da branch Exemplo Peso da revisão
Novo endpoint feat/api- feat/api-invoices-list Padrão
Campo aditivo feat/api- feat/api-invoice-currency Leve
Breaking change break/api- break/api-remove-legacy-id Pesado, requer aprovação
Correção na especificação fix/api- fix/api-status-enum-typo Leve
Refatoração semântica zero chore/api- chore/api-reorder-schemas Leve

O prefixo ajuda revisores e automações. Uma branch break/api- deve acionar revisão mais rigorosa e análise de consumidores afetados.

Trunk-based ou Gitflow?

Modelo Melhor para Impacto na API
Trunk-based Entrega contínua, equipes pequenas ou médias Contrato evolui em passos pequenos; menos conflitos
Gitflow Lançamentos agendados ou regulados Especificação pode divergir em develop; merges maiores

Para a maioria das equipes, prefira trunk-based development:

git checkout -b feat/api-new-field
# altera a spec
git commit -m "Add currency field to invoice"
git push origin feat/api-new-field
# abre PR e faz merge em main
Enter fullscreen mode Exit fullscreen mode

Branches curtas reduzem conflitos em YAML e tornam a revisão mais objetiva.

Como revisar design de API em pull requests

Um PR de especificação não é apenas uma checagem de sintaxe. Ele é uma revisão de design.

Use este checklist:

1. A mudança quebra consumidores existentes?

Breaking changes incluem:

  • Remover campo.
  • Renomear propriedade.
  • Remover valor de enum.
  • Tornar campo opcional em obrigatório.
  • Alterar tipo de dado.
  • Remover endpoint.
  • Mudar estrutura de erro.

Exemplo de alteração aditiva:

 parameters:
   - name: status
     in: query
     schema:
       type: string
-      enum: [draft, open, paid, void]
+      enum: [draft, open, paid, void, uncollectible]
Enter fullscreen mode Exit fullscreen mode

Adicionar uncollectible é menos arriscado do que remover void. Se um valor existente desaparece, clientes podem quebrar.

2. A nomenclatura é consistente?

Verifique se o novo endpoint segue os padrões existentes:

GET /users/{userId}/invoices
GET /users/{userId}/payments
GET /users/{userId}/subscriptions
Enter fullscreen mode Exit fullscreen mode

Evite misturar estilos:

GET /user/{userId}/invoice-list
Enter fullscreen mode Exit fullscreen mode

3. O modelo de erro é o mesmo?

Se a API já usa:

{
  "code": "USER_NOT_FOUND",
  "message": "User not found"
}
Enter fullscreen mode Exit fullscreen mode

não introduza outro formato sem motivo:

{
  "error": "missing user"
}
Enter fullscreen mode Exit fullscreen mode

4. O diff é legível?

Mantenha o YAML estável:

  • Ordene chaves de forma consistente.
  • Não reordene arquivos inteiros em PRs funcionais.
  • Separe refatorações de mudanças semânticas.
  • Adicione novos paths em locais previsíveis.

Um diff pequeno recebe revisão real. Um arquivo inteiro reformatado esconde a mudança importante.

Do design ao desenvolvimento

Depois que o contrato entra em main, ele deve alimentar o restante do fluxo.

1. Gere código

Use ferramentas como openapi-generator para gerar clientes ou stubs.

Exemplo:

npx @openapitools/openapi-generator-cli generate \
  -i api/openapi.yaml \
  -g typescript-fetch \
  -o generated/api-client
Enter fullscreen mode Exit fullscreen mode

Para stubs de servidor:

npx @openapitools/openapi-generator-cli generate \
  -i api/openapi.yaml \
  -g nodejs-express-server \
  -o generated/server
Enter fullscreen mode Exit fullscreen mode

A lógica de negócio ainda é implementada pela equipe, mas os formatos de request e response vêm da especificação.

2. Gere mocks

Um mock server permite que o frontend comece antes do backend.

Exemplo com Prism:

npx @stoplight/prism-cli mock api/openapi.yaml
Enter fullscreen mode Exit fullscreen mode

Agora consumidores podem chamar endpoints simulados com base no contrato aprovado.

3. Rode testes de contrato

Testes de contrato validam se o servidor real respeita a especificação.

Fluxo típico:

  1. Sobe a aplicação.
  2. Envia requests reais.
  3. Valida responses contra o OpenAPI.
  4. Falha o CI se houver divergência.

Isso impede o problema clássico: a especificação diz uma coisa, mas o servidor faz outra.

4. Gere documentação

A documentação de referência deve ser renderizada a partir do OpenAPI. Assim, quando o contrato muda, a documentação muda junto.

O princípio é sempre o mesmo: gere artefatos a partir da especificação confirmada. Não mantenha clientes, mocks ou documentação manualmente quando eles podem derivar do contrato.

Convenções de equipe que escalam

Um fluxo git-native funciona melhor quando a equipe define regras explícitas.

1. Escolha a estrutura dos arquivos

Para APIs pequenas, um único arquivo pode bastar:

api/openapi.yaml
Enter fullscreen mode Exit fullscreen mode

Para APIs maiores, divida por recurso:

api/
  openapi.yaml
  paths/
    users.yaml
    invoices.yaml
  components/
    schemas/
      invoice.yaml
      user.yaml
Enter fullscreen mode Exit fullscreen mode

Depois, empacote na build:

npx swagger-cli bundle api/openapi.yaml -o dist/openapi.yaml
Enter fullscreen mode Exit fullscreen mode

2. Versione deliberadamente

Atualize info.version em mudanças relevantes.

Exemplo:

info:
  title: Billing API
  version: 1.4.0
Enter fullscreen mode Exit fullscreen mode

Regra prática:

  • Campo ou endpoint aditivo: versão minor.
  • Correção sem mudança de contrato: versão patch.
  • Breaking change: versão major, geralmente com novo prefixo como /v2.

3. Mantenha um changelog

Use um CHANGELOG.md ao lado da especificação:

# Changelog

## 1.4.0

- Added `GET /users/{userId}/invoices`.
- Added `currency` field to `Invoice`.
Enter fullscreen mode Exit fullscreen mode

O Git é preciso, mas o changelog é mais fácil para consumidores humanos.

4. Proteja a especificação com CODEOWNERS

Exija aprovação dos responsáveis pela API:

# .github/CODEOWNERS
/api/openapi.yaml @api-stewards
/api/paths/ @api-stewards
/api/components/ @api-stewards
Enter fullscreen mode Exit fullscreen mode

Assim, qualquer alteração no contrato passa por revisão especializada.

5. Faça lint no CI

Exemplo com Spectral no GitHub Actions:

# .github/workflows/api-lint.yml
name: API Lint

on:
  pull_request:
    paths:
      - "api/**"

jobs:
  spectral:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Run Spectral
        run: npx @stoplight/spectral-cli lint api/openapi.yaml --fail-severity warn
Enter fullscreen mode Exit fullscreen mode

Com lint no CI e CODEOWNERS, cada alteração recebe duas camadas de proteção:

  • Regras automáticas.
  • Revisão humana.

Armadilhas comuns e como evitá-las

Divergência entre especificação e código

Problema: o contrato diz uma coisa, o servidor responde outra.

Como evitar:

  • Gere stubs e clientes a partir do OpenAPI.
  • Rode testes de contrato no CI.
  • Falhe a build quando a resposta real não bater com o schema.

PRs grandes demais

Problema: uma branch adiciona muitos endpoints e ninguém revisa de verdade.

Como evitar:

  • Um endpoint ou uma mudança semântica por PR.
  • Refatorações em PRs separados.
  • Commits pequenos e mensagens claras.

Artefatos manuais

Problema: cliente, mock ou documentação escritos manualmente ficam desatualizados.

Como evitar:

  • Gere clientes.
  • Gere mocks.
  • Gere documentação.
  • Trate artefatos manuais como exceção.

Conflitos de merge em YAML

Problema: duas branches longas alteram a mesma região do arquivo.

Como evitar:

  • Branches curtas.
  • Ordem estável de chaves.
  • Especificação dividida em múltiplos arquivos.
  • Trunk-based development sempre que possível.

Onde o Apidog se encaixa

Você pode executar um fluxo git-native com editor de texto, Git e CLI. Mas muitas equipes querem uma interface visual para desenhar APIs sem abandonar o Git como fonte da verdade.

O Modo Spec-First do Apidog cobre esse cenário. Ele mantém o arquivo OpenAPI no seu repositório Git e oferece sincronização bidirecional: você pode editar no designer visual do Apidog ou no editor de código, mantendo consistência com o arquivo versionado.

O ponto principal é que o Git continua canônico. Branches, PRs, histórico e revisão continuam funcionando como descrito neste guia. O Apidog vira uma interface sobre a especificação, não um substituto para o repositório.

Consulte a documentação do Modo Spec-First para detalhes de configuração.

FAQ

O design de API git-native é apenas para OpenAPI?

Não. A disciplina se aplica a qualquer contrato baseado em texto:

  • OpenAPI.
  • AsyncAPI.
  • Arquivos .proto do gRPC.
  • GraphQL SDL.

Se o contrato pode ser versionado, comparado com diff, revisado em PR e revertido, ele pode seguir um fluxo git-native.

Como lidar com breaking changes?

Torne a quebra explícita:

  1. Use branch com prefixo break/api-.
  2. Atualize a versão principal.
  3. Exija aprovação via CODEOWNERS.
  4. Documente a mudança no changelog.
  5. Quando possível, adicione a nova estrutura ao lado da antiga e deprecie a versão anterior.

Exemplo:

break/api-remove-legacy-id
Enter fullscreen mode Exit fullscreen mode

O nome da branch já comunica que a revisão precisa ser mais rigorosa.

A especificação deve ficar no mesmo repositório que o código?

Geralmente sim, quando a mesma equipe mantém API e implementação.

Vantagens:

  • Um PR pode alterar contrato e handler.
  • Testes de contrato rodam na mesma pipeline.
  • A equipe vê implementação e especificação juntas.

Use um repositório separado quando a API for compartilhada por muitas equipes e precisar de versionamento independente.

Como evitar que especificação e código se distanciem?

Adicione testes de contrato ao CI.

O fluxo mínimo é:

# 1. sobe o servidor
npm run start:test

# 2. executa testes que chamam endpoints reais
npm run test:contract
Enter fullscreen mode Exit fullscreen mode

A build deve falhar se uma resposta não cumprir o schema OpenAPI. Combinado com codegen, isso transforma divergência em erro de pipeline, não em bug de produção.

Conclusão

Design de API git-native é uma disciplina: trate o contrato como código-fonte, evolua em branches, revise em pull requests e gere artefatos a partir da especificação confirmada.

Comece pequeno:

  1. Coloque a especificação no repositório.
  2. Adicione lint no CI.
  3. Proteja arquivos de contrato com CODEOWNERS.
  4. Faça PRs pequenos.
  5. Gere clientes, mocks e documentação.
  6. Adicione testes de contrato.

A partir daí, o fluxo escala naturalmente. Cada merge em main passa a registrar não só uma mudança de código, mas uma decisão formal sobre a evolução da sua API.

Top comments (0)