Estratégias de Versionamento de API: Breaking changes sem quebrar clientes

Sua API é um contrato entre você e seus clientes (aplicações mobile, SPA, parceiros). Um dia, você precisa adicionar um campo obrigatório, renomear uma propriedade ou remover um endpoint obsoleto. Como fazer isso sem quebrar todos os clientes existentes? A resposta é versionamento de API.

Versionar APIs é inevitável. O problema não é se versionar, mas como. Neste post, vamos explorar as principais estratégias de versionamento (URI, header, query parameter, content negotiation), quando usar cada uma, como comunicar deprecação e como manter compatibilidade retroativa – com exemplos em HTTP/REST, gRPC e práticas que a Jacobus aplica em projetos reais.

Por que versionar?

APIs evoluem. Bugs são corrigidos, novos campos são adicionados, requisitos mudam. Sem versionamento, você tem duas opções ruins:

  1. Quebrar clientes existentes – eles param de funcionar, você perde negócio.
  2. Nunca mudar a API – você fica preso a decisões antigas, não inova.

Versionamento permite que ambos coexistam: clientes antigos usam a versão antiga; clientes novos usam a nova.

Estratégias de versionamento para REST APIs

EstratégiaExemploPrósContras
URL path/v1/users, /v2/usersSimples, visível, fácil cache“Polui” a URL, difícil gerenciar múltiplas versões no código
Query parameter/users?version=1Fácil de implementarCache pode ignorar query param; pouco idiomático
Custom headerAccept: application/vnd.myapi.v1+jsonLimpo, sem poluir URLClientes precisam configurar header; menos visível
Content negotiationAccept: application/json; version=1Padrão HTTPComplexo, muitos clientes não suportam

1. Versionamento por URL Path (recomendado pela Jacobus)

É a estratégia mais comum e intuitiva. A versão fica no path da URL.

GET /v1/users/123
GET /v2/users/123

Exemplo em Go (usando gorilla/mux ou net/http):

router := http.NewServeMux()
// v1 handler
router.HandleFunc("/v1/users/", handleGetUserV1)
// v2 handler (pode chamar a mesma lógica ou diferente)
router.HandleFunc("/v2/users/", handleGetUserV2)

func handleGetUserV1(w http.ResponseWriter, r *http.Request) {
    // retorna User com campos antigos
}

func handleGetUserV2(w http.ResponseWriter, r *http.Request) {
    // retorna User com novos campos
}

Vantagens: fácil de rotear (Kubernetes Ingress, API Gateway), cache funciona por URL, claro para clientes.

2. Versionamento por Custom Header

GET /users/123
X-API-Version: 1

Em Go, leia o header:

func handleGetUser(w http.ResponseWriter, r *http.Request) {
    version := r.Header.Get("X-API-Version")
    switch version {
    case "1":
        serveV1(w, r)
    case "2":
        serveV2(w, r)
    default:
        serveV1(w, r) // default
    }
}

Quando usar: quando URLs limpas são importantes (ex: API pública de alta visibilidade) ou você quer forçar clientes a declarar versão explicitamente.

3. Versionamento por Accept Header (Content Negotiation)

GET /users/123
Accept: application/vnd.mycompany.user.v1+json

É o padrão RESTful mais “puro”, mas raramente usado por sua complexidade.

Como lidar com breaking changes sem quebrar clientes

Mesmo com versionamento, mudanças podem quebrar clientes se você não planejar. Boas práticas:

Mudanças compatíveis (não exigem nova versão)

MudançaExemploÉ breaking?
Adicionar campo opcional{ "name": "João", "age": 30 }{ ..., "email": "joao@email.com" }❌ Não
Adicionar novo endpointGET /v1/users → também GET /v1/users/123/orders❌ Não
Ampliar valores de enumstatus: "active""active", "suspended" (desde que clientes tratem desconhecidos)❌ Não
Mudar ordem de camposObjeto JSON reordenado❌ Não (ordem não importa)

Mudanças incompatíveis (exigem nova versão)

MudançaExemploSolução
Remover campo{ "name": ... }{}Marcar como deprecated por uma versão, depois remover na v2
Renomear campo"user_id""userId"Aceitar ambos por um período, depois remover o antigo
Mudar tipo de campo"age": "30" (string) → "age": 30 (int)Nova versão
Tornar campo obrigatórioemail opcional → obrigatórioNova versão

Estratégia de deprecação (deprecation)

Uma versão não pode morrer do dia para a noite. Use um ciclo de deprecação:

  1. Anuncie com antecedência – informe que a versão V1 será descontinuada em 6 meses.
  2. Adicione headers de aviso – retorne Warning: 299 - "Deprecated" ou Deprecation: true.
  3. Monitore uso – veja quais clientes ainda usam a versão antiga.
  4. Após o prazo, retorne 410 Gone – mas considere manter em modo “read-only” para clientes teimosos.

Exemplo de headers de deprecação (RFC 8594):

HTTP/1.1 200 OK
Deprecation: true
Sunset: Sat, 31 Dec 2026 23:59:59 GMT
Link: <http://api.example.com/v2/docs>; rel="latest-version"

Em Go:

w.Header().Set("Deprecation", "true")
w.Header().Set("Sunset", "Sat, 31 Dec 2026 23:59:59 GMT")
w.Header().Set("Link", `<http://api.example.com/v2/docs>; rel="latest-version"`)

Versionamento em gRPC

gRPC tem um mecanismo diferente: protocol buffers (protobuf). Mudanças compatíveis são muito mais fáceis.

Regras de compatibilidade protobuf (mesma versão de serviço)

Adicionar novo campo – desde que use números novos e não obrigatório (não use required).
Renomear campo – o número do campo é o identificador, nome é apenas metadado.
Remover campo – reserve o número (com reserved) para não reutilizar.
Adicionar novo método na service.

Mudar tipo de campo – incompatível.
Mudar número de campo – incompatível.
Remover método – quebra clientes.

Versionamento semântico para APIs gRPC

Use diferentes pacotes protobuf para versões diferentes:

// v1/api.proto
package api.v1;

service UserService {
    rpc GetUser(GetUserRequest) returns (User);
}

// v2/api.proto
package api.v2;

service UserService {
    rpc GetUser(GetUserRequestV2) returns (UserV2);
}

No servidor, registre ambas as implementações.

Versionamento em filas e eventos (mensageria)

Se você publica eventos em Kafka/RabbitMQ/NATS, versionamento também é essencial.

Boas práticas:

  • Inclua version no envelope da mensagem.
  • Use esquemas compatíveis (Avro, Protobuf, JSON Schema) com evolução.
  • Consumidores ignoram campos que não conhecem.
  • Adicione deprecated em campos que serão removidos no futuro.
{
  "version": 1,
  "event_type": "order.created",
  "data": {
    "order_id": "123",
    "total": 100.50
  }
}

Estratégia de “mantenha duas versões simultâneas”

Na prática, você raramente quer manter mais de duas versões ativas (ex: v1 e v2). Crie uma política:

  • Versão atual (última) – recebe novas funcionalidades.
  • Versão anterior – apenas correções de segurança e bugs críticos.
  • Versões mais antigas – descontinuadas (410 Gone).

Ferramentas para auxiliar versionamento

FerramentaFunção
OpenAPI (Swagger)Documentar versões da API, gerar clientes, validar mudanças
Buf (para gRPC)Checa compatibilidade protobuf em CI
GraphQLNão tem versionamento explícito – use deprecação de campos
API GatewayPode rotear diferentes versões para diferentes backends

Caso real: API de pagamentos com versionamento

Um cliente da Jacobus (fintech) tinha APIs não versionadas. Quando precisaram adicionar um novo campo installments no payload de pagamento, clientes antigos quebravam porque enviavam o payload sem o campo. Implementamos:

  • Versionamento via URL path (/v1/payments, /v2/payments).
  • Documentação OpenAPI para cada versão.
  • Proxy no API Gateway roteando com base no path.
  • Deprecação gradual da v1 com header Deprecation e Sunset após 1 ano.

Resultado: zero downtime para clientes existentes; novos clientes usam v2; migração completa em 8 meses sem incidentes.

Conclusão

Versionamento de API não é opcional – é garantia de evolução sem destruir quem depende de você. Prefira URL path para REST (mais simples e cacheável) e protobuf com pacotes separados para gRPC. Anuncie deprecação com headers, mantenha no máximo duas versões ativas e documente tudo.

Na Jacobus Software, projetamos APIs que evoluem com o negócio, não contra ele. Se você ainda não versiona suas APIs, comece hoje – seus clientes (futuros) agradecerão.


🔄 Quer versionar suas APIs sem quebrar clientes?

Nossos especialistas ajudam a planejar e implementar estratégias de versionamento, documentação OpenAPI e deprecação segura.

👉 Fale com a Jacobus Software

Rolar para cima