A maioria das equipes de API trata o contrato como algo secundário. Elas escrevem o código primeiro, depois geram uma especificação e, então, observam os dois se distanciarem. O design de API Git-native inverte essa ordem. Você trata o contrato da API como código-fonte, versiona-o no Git e revisa cada alteração da mesma forma que revisa a lógica do aplicativo.
Este guia é sobre a disciplina, não sobre uma única ferramenta. Você aprenderá como projetar contratos em branches, revisá-los em pull requests e transformar uma especificação confirmada em mocks, testes e documentação. O objetivo é um fluxo de trabalho onde seu histórico do Git *é* o histórico da sua API.
Se você já sabe como são as ferramentas Spec-First e quer a apresentação do produto, leia o artigo complementar sobre o fluxo de trabalho de API git-native. Este artigo mantém o foco na prática.
O que “git-native” significa para o trabalho com APIs
Git-native significa que sua definição de API vive em seu repositório como um arquivo de texto simples. Não em um banco de dados proprietário na nuvem. Não atrás de um login de fornecedor. Um arquivo .yaml ou .json ao lado do seu código, rastreado pelo mesmo controle de versão que sua equipe já usa.
Contraste isso com ferramentas presas à nuvem. Muitas plataformas de design de API armazenam o contrato em seu próprio backend. Você edita através de uma interface web, e a versão canônica reside em seus servidores. Seu repositório detém, na melhor das hipóteses, uma exportação desatualizada. Quando o banco de dados do fornecedor é a fonte da verdade, seu histórico do Git não diz nada sobre como a API evoluiu.

O modelo git-native inverte essa relação. O arquivo em main é o contrato. Todo o resto, incluindo qualquer interface gráfica, é uma visualização desse arquivo. Essa única mudança desbloqueia o histórico, o blame, o rollback e a revisão para a sua superfície de API.
Uma configuração git-native possui três propriedades. A especificação é um arquivo de texto no repositório. As alterações fluem através das operações normais do Git, como branch, commit e merge. E cada artefato subsequente, de mocks a documentação, deriva do arquivo confirmado em vez de um banco de dados separado.
Por que projetar e desenvolver APIs no Git
Você já confia no Git com seu ativo mais valioso: seu código. Seu contrato de API merece o mesmo tratamento.
O histórico é a primeira razão. Quando alguém pergunta “quando adicionamos o parâmetro de paginação cursor,” git log responde em segundos. O commit que o introduziu carrega uma mensagem, um autor e uma data. Sem capturas de tela, sem arqueologia de changelog.
O blame é o segundo. Execute git blame no arquivo de especificação e você verá exatamente quem alterou cada linha e por quê. Um nome de campo confuso remonta ao PR que o adicionou, com a discussão anexada. A responsabilização se torna automática.
O rollback é o terceiro. Um design ruim é lançado. Com o Git, você git revert o merge e o contrato retorna ao seu estado anterior. A geração de código, mocks e documentação subsequentes são regenerados a partir do arquivo revertido. Não há limpeza manual em um sistema separado.
A revisão é o quarto, e é o que as equipes subutilizam. Um pull request é o local natural para debater um design de API *antes* que ele se torne real. Os revisores comentam em uma linha + que adiciona um campo obrigatório. A conversa permanece ao lado da alteração para sempre.
Uma única fonte de verdade une tudo. Quando o contrato é um arquivo em main, não há ambiguidade sobre qual versão é a real. Frontend, backend, QA e documentação leem a mesma linha YAML. Esta é a promessa central de um fluxo de trabalho de especificação de API baseado em Git.
O ciclo de design de API git-native
O ciclo tem cinco etapas: projetar o contrato, fazer commit, abrir um PR, revisar e fazer merge. A implementação segue o merge, e não o contrário.
Comece escrevendo o contrato. Suponha que você esteja adicionando um endpoint para buscar as faturas de um usuário. Você cria uma branch e edita o arquivo OpenAPI.
# openapi.yaml (excerpt added on branch feat/invoices-list)
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
Confirme essa alteração com uma mensagem clara: git commit -m "Add GET /users/{userId}/invoices contract". O commit é pequeno e focado. Ele descreve uma decisão de design.
Agora, abra um pull request. O diff mostra aos revisores exatamente o que é novo: um caminho, uma operação, dois parâmetros, duas respostas. Seus colegas de equipe discutem a nomenclatura, os valores do enum e se 404 é o código certo para um usuário inexistente. Eles podem insistir na paginação por cursor antes que uma única linha de código do handler exista.
Assim que o PR for aprovado, faça o merge. O contrato em main agora inclui o endpoint de faturas. A implementação vem a seguir, e é limitada pela especificação que todos vocês concordaram. Essa ordem é o que as pessoas querem dizer com desenvolvimento de API spec-first: o acordo precede o código.
A vantagem é que os debates de design acontecem de forma barata. Alterar um campo YAML em revisão custa minutos. Alterar um endpoint lançado, implementado e documentado custa dias.
Estratégia de branching para contratos de API
Trate as alterações de contrato como qualquer outra alteração: uma branch por unidade lógica de trabalho. Uma branch por endpoint ou por modificação mantém os PRs pequenos e os diffs legíveis.
Nomeie as branches para que a intenção seja óbvia. Use um prefixo que sinalize a classe da alteração. Isso ajuda revisores e CI a direcionar o trabalho.
| 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 |
| Alteração disruptiva (Breaking change) | break/api- |
break/api-remove-legacy-id |
Pesado, requer aprovação |
| Correção de bug na especificação | fix/api- |
fix/api-status-enum-typo |
Leve |
| Apenas refatoração | chore/api- |
chore/api-reorder-schemas |
Leve |
O prefixo carrega significado. Uma branch break/api- diz aos revisores para ir com calma e verificar cada consumidor. Uma branch chore/api- sinaliza que não há alteração semântica, então a revisão pode ser rápida.
Você também escolhe um modelo de branching. O desenvolvimento baseado em trunk (Trunk-based development) é adequado para a maioria das equipes de API. Branches de curta duração são mescladas em main diariamente, e a especificação permanece próxima de uma única linha de verdade. O Gitflow, com branches de longa duração develop e release, se encaixa em equipes que agrupam alterações de API em lançamentos programados.
| Modelo | Melhor para | Compromisso da API |
|---|---|---|
| Baseado em Trunk | Entrega contínua, equipes pequenas | Contrato evolui em pequenos passos; menos problemas de merge |
| Gitflow | Lançamentos agendados, entregas reguladas | Especificação diverge em develop; merges maiores e mais arriscados |
Para a maioria do trabalho com APIs, prefira o desenvolvimento baseado em trunk. Alterações pequenas e frequentes no contrato produzem diffs pequenos e frequentes. Branches de longa duração permitem que a especificação se afaste, e conflitos de merge YAML ficam feios rapidamente quando duas branches reestruturam o mesmo arquivo.
Revisando o design da API em pull requests
Um PR de especificação é uma revisão de design, não uma verificação de sintaxe. Os revisores olham para a semântica, e algumas perguntas cobrem a maior parte do risco.
Isso quebra consumidores existentes? Remover um campo, renomear um caminho ou restringir um tipo são todas alterações disruptivas. Um revisor verifica se a alteração é aditiva ou disruptiva, e as alterações disruptivas exigem um aumento de versão ou um caminho de depreciação.
A nomenclatura é consistente? Se cada endpoint de coleção usa substantivos plurais, um novo caminho singular se destaca. Se os erros retornam um campo code em outro lugar, um novo endpoint também deveria. Os revisores impõem os padrões que a API já estabeleceu.
É amigável para diff? Mantenha o YAML estável para que os diffs permaneçam pequenos. Ordene as chaves de forma consistente. Adicione novos caminhos em um local previsível. Um revisor pode ler um diff de cinco linhas em segundos, mas um arquivo reordenado produz um diff de cem linhas que oculta a verdadeira alteração.
alteração disruptiva amigável para o revisor. As linhas - sinalizam exatamente o que desaparece.
# Diff a reviewer sees in the PR
parameters:
- name: status
in: query
schema:
type: string
- enum: [draft, open, paid, void]
+ enum: [draft, open, paid, void, uncollectible]
Esse diff é aditivo ao enum, então é seguro. Compare-o com uma linha - que remove void completamente, o que quebraria qualquer cliente que enviasse esse valor. O diff torna a diferença visível em um piscar de olhos.
Incentive os revisores a comentar inline na especificação, da mesma forma que comentam no código. A discussão permanece anexada à linha e sobrevive no histórico mesclado.
Do design ao desenvolvimento
Uma vez que o contrato está em main, ele se torna a fonte para tudo o que vem a seguir. Você gera, não escreve manualmente.

A geração de código (codegen) vem primeiro. Ferramentas como openapi-generator produzem stubs de servidor e clientes tipados a partir do arquivo confirmado. Seus handlers preenchem a lógica de negócios, mas as formas de requisição e resposta correspondem ao contrato por construção. A especificação e o código não podem discordar sobre o formato de comunicação.
Mocks vêm em seguida. Um servidor mock lê a especificação e retorna respostas de exemplo para cada endpoint. Desenvolvedores frontend constroem contra o mock antes que o backend exista. Eles começam no momento em que o contrato é mesclado, não semanas depois.
Testes seguem. Testes de contrato afirmam que seu servidor em execução corresponde à especificação. Envie uma requisição, valide a resposta contra o esquema e falhe a build se eles divergirem. Esta é a salvaguarda contra a divergência entre especificação e código.
A documentação também é gerada. A documentação de referência é renderizada diretamente do arquivo OpenAPI. Quando o contrato muda, a documentação muda no mesmo commit. Não há uma atualização de documentação separada para esquecer.
O princípio é consistente. Cada artefato deriva de um arquivo confirmado. Regenere a cada merge, e seus mocks, clientes, testes e documentação permanecerão sincronizados com o contrato.
Convenções de equipe que escalam
Convenções são o que impedem que um fluxo de trabalho git-native entre em colapso à medida que a equipe cresce. Decida-as cedo e anote-as.
Primeiro, escolha entre um arquivo de especificação e muitos. Um único openapi.yaml é simples, mas se torna difícil de manejar após algumas dezenas de endpoints. Dividir em vários arquivos com referências $ref mantém cada arquivo legível, ao custo de uma etapa de empacotamento. Um padrão comum é um arquivo por recurso, empacotado em uma única especificação no momento da build.
Segundo, faça o versionamento deliberadamente. Atualize o info.version do OpenAPI a cada alteração significativa e siga o versionamento semântico. Alterações aditivas aumentam a versão secundária. Alterações disruptivas (breaking changes) aumentam a versão principal e geralmente significam um novo prefixo de caminho como /v2/.
Terceiro, mantenha um changelog. Um CHANGELOG.md ao lado da especificação registra o que mudou e por que em termos humanos. O histórico do Git é preciso, mas verboso; o changelog é o resumo legível que seus consumidores realmente consultam.
Quarto, proteja a especificação com CODEOWNERS. Exija que os guardiões da API aprovem qualquer alteração no arquivo do contrato. Isso impede que contribuidores bem-intencionados lancem designs inconsistentes.
# .github/CODEOWNERS
/api/openapi.yaml @api-stewards
/api/paths/ @api-stewards
Quinto, faça lint no CI. Um linter detecta problemas de estilo e consistência antes da revisão. Execute-o em cada PR para que os humanos revisem o design, não a formatação.
# .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
Com linting no CI mais CODEOWNERS, cada alteração de contrato recebe verificações automatizadas e um guardião humano. Essa combinação escala de três engenheiros para trezentos.
Armadilhas comuns e como evitá-las
O design de API git-native possui modos de falha previsíveis. Conhecê-los permite que você projete contornando-os.
A divergência entre especificação e código (spec/code drift) é a pior. O contrato diz uma coisa; o servidor em execução faz outra. Previna isso com testes de contrato no CI que validam respostas reais contra a especificação confirmada. Se eles divergirem, a build falha. A divergência se torna uma pipeline quebrada, não uma surpresa em produção.
PRs gigantes são a próxima armadilha. Uma única branch que adiciona vinte endpoints produz um diff inrevisável. Os revisores apenas olham por cima, aprovam e perdem problemas. Divida o trabalho em um endpoint ou uma alteração por PR. Diffs pequenos recebem uma revisão real.
Artefatos escritos manualmente causam inconsistência silenciosa. Quando alguém escreve um cliente manualmente em vez de gerá-lo, o cliente se distancia da especificação. Gere clientes, stubs e documentação a partir do arquivo confirmado todas as vezes. Trate artefatos de API escritos manualmente como um sinal de alerta.
Conflitos de merge YAML frustram equipes em branches de longa duração. Duas branches reestruturam o mesmo arquivo e o Git não consegue conciliá-los. Evite isso com branches de curta duração, uma ordem de chaves estável e um layout de arquivo dividido para que as alterações toquem em arquivos diferentes. O desenvolvimento baseado em trunk mais PRs pequenos remove a maioria dos conflitos antes que eles comecem.
O padrão em todos os quatro é o mesmo. Mantenha as alterações pequenas, derive artefatos da especificação e deixe o CI impor o contrato. Disciplina supera heroísmos.
Onde o Apidog se encaixa
Você pode executar um fluxo de trabalho git-native com um editor de texto e uma CLI. Muitas equipes querem uma interface gráfica para design sem abrir mão do Git como fonte da verdade. Essa é a lacuna que o Modo Spec-First do Apidog preenche.
O Modo Spec-First mantém o arquivo OpenAPI em seu repositório Git e possui sincronização bidirecional. Você edita o contrato no designer visual do Apidog ou em seu editor, e ambos permanecem consistentes com o arquivo em seu repositório. O arquivo no Git permanece canônico, então branches, PRs e histórico funcionam exatamente como descrito aqui. Você obtém a interface gráfica sem a dependência da nuvem. Consulte a documentação do Modo Spec-First para detalhes de configuração.
O ponto não é a ferramenta. É que você pode ter uma superfície de design visual e uma disciplina git-native ao mesmo tempo. O repositório permanece a única fonte de verdade, e o Apidog se torna uma das visualizações sobre ele.
FAQ
O design de API git-native é apenas para OpenAPI?
Não. A disciplina se aplica a qualquer formato de contrato baseado em texto. OpenAPI é o mais comum, mas o mesmo fluxo de trabalho funciona para AsyncAPI, arquivos .proto do gRPC ou GraphQL SDL. Contanto que o contrato seja um arquivo de texto que você possa comparar (diff), ramificar (branch) e revisar, ele é git-native.
Como lido com alterações disruptivas em um fluxo de trabalho git-native?
Torne as alterações disruptivas visíveis e deliberadas. Use um prefixo de branch break/api-, aumente a versão principal e exija a aprovação do guardião através de CODEOWNERS. Onde possível, adicione a nova estrutura ao lado da antiga e deprecie o caminho antigo em um cronograma. O diff do PR e o aumento de versão juntos sinalizam a quebra para cada consumidor.
A especificação da API deve viver no mesmo repositório que o código?
Geralmente sim, quando uma equipe é proprietária de ambos. A co-localização da especificação e da implementação significa que um único PR pode alterar o contrato e o handler juntos, e os testes de contrato são executados em uma única pipeline. Coloque a especificação em um repositório separado apenas quando muitas equipes consomem uma API compartilhada e precisam de versionamento independente.
Como evito que a especificação e o código se distanciem?
Adicione testes de contrato ao CI. Eles enviam requisições reais ao seu servidor em execução e validam cada resposta contra a especificação confirmada. Uma divergência falha a build. Combinado com a geração de stubs e clientes a partir da especificação, os testes de contrato transformam a divergência em uma falha de pipeline em vez de um bug de produção.
Conclusão
O design de API git-native é uma disciplina, não um produto. Você trata o contrato como código-fonte, o evolui em branches, o revisa em pull requests e gera cada artefato subsequente a partir do arquivo confirmado. Histórico, blame, rollback e revisão vêm de graça porque o Git já os oferece a você.
Comece pequeno. Mova sua especificação para o repositório, adicione uma etapa de lint e exija revisão nas alterações de contrato. A partir daí, construa com codegen, mocks e testes de contrato. O fluxo de trabalho se expande: cada convenção facilita a próxima, e seu histórico do Git se torna um registro completo de como sua API evoluiu.
Se você deseja uma superfície de design visual que mantenha a especificação no Git, experimente o Modo Spec-First no Apidog e veja como a sincronização bidirecional se encaixa no fluxo de trabalho acima.
