No design arquitetônico de sistemas distribuídos, as APIs não são apenas condutos para a interação do sistema; elas são contratos que conectam diferentes pilhas tecnológicas, culturas organizacionais e até eras de desenvolvimento. Dentro dos detalhes de design das APIs RESTful, um tópico aparentemente menor gera um debate interminável: Os nomes dos campos JSON devem usar camelCase ou snake_case?
Esta não é meramente uma escolha estética. Ela aborda o "impedimento de incompatibilidade" (impedance mismatch) entre as camadas de persistência de backend e as camadas de apresentação de frontend, envolvendo desempenho de serialização, eficiência de transmissão de rede, Experiência do Desenvolvedor (DX) e psicologia cognitiva.
Com base na história das linguagens de programação, nos mecanismos de implementação técnica subjacentes e nas decisões arquitetônicas de gigantes da indústria como Google e Stripe, este artigo fornece um guia de decisão de nível especializado.
1. Origens Históricas: Uma Escolha Semiótica
Para entender este debate, devemos rastrear a evolução das linguagens de computador. As convenções de nomenclatura não surgiram do nada; são produtos de limitações de hardware e culturas comunitárias de eras específicas.
A Origem do snake_case: C e a Filosofia Unix
A popularidade do snake_case (ex: user_id) remonta ao C e ao Unix na década de 1970. Embora os teclados antigos (como o Teletype Modelo 33) tivessem teclas shift, muitos compiladores antigos eram insensíveis a maiúsculas e minúsculas. Para distinguir palavras claramente em telas de baixa resolução, os programadores introduziram o sublinhado para simular espaços na linguagem natural. Esse hábito tornou-se profundamente enraizado nos padrões de banco de dados SQL. Até hoje, o estilo padrão de nomenclatura de colunas para PostgreSQL e MySQL permanece snake_case, estabelecendo as bases para o futuro atrito de mapeamento entre APIs e bancos de dados.
A Ascensão do camelCase: A Hegemonia de Java e JavaScript
camelCase (ex: userId) surgiu com a Programação Orientada a Objetos (Smalltalk, C++, Java). Java estabeleceu o padrão industrial de "PascalCase para classes, camelCase para métodos/variáveis". O ponto de virada decisivo foi o nascimento do JavaScript. Embora o JSON tenha se originado de literais de objeto JS, a biblioteca padrão JS (ex: getElementById) adotou o camelCase em toda a linha. À medida que AJAX e JSON substituíram o XML como os formatos dominantes de troca de dados, camelCase ganhou status "nativo" no domínio da Web.
2. Conflito Central: Incompatibilidade de Impedância de Pilhas Tecnológicas
Quando os dados fluem entre diferentes linguagens, eles inevitavelmente encontram uma "incompatibilidade de impedância" (impedance mismatch).
A Perspectiva do Backend (Python/Ruby/SQL)
No backend, as comunidades Python (PEP 8) e Ruby recomendam fortemente o snake_case.
- Python/Django/FastAPI: Seus modelos Pydantic geralmente correspondem diretamente às estruturas de tabela do banco de dados:
class UserProfile(BaseModel):
first_name: str # Python convention
last_name: strSe a API exige camelCase, você deve configurar apelidos ou conversores na camada de serialização. Embora viável, isso adiciona uma camada de lógica de mapeamento.
- Bancos de Dados SQL: A maioria dos nomes de coluna de banco de dados usa
snake_case. Se a API usacamelCase, a camada ORM deve lidar consistentemente com a conversão. - A Escolha da Stripe: A razão pela qual Stripe e GitHub escolheram firmemente
snake_caseé em grande parte porque suas arquiteturas iniciais foram construídas na pilha Ruby. Expor modelos internos diretamente garantia a consistência do backend.
A Perspectiva do Frontend (JavaScript/TypeScript)
No navegador, camelCase é o rei absoluto.
- Fragmentação do Estilo de Código: Se uma API retorna
snake_case, o código frontend se torna inconsistente:
const user = await fetchUser();
console.log(user.first_name); // Violates ESLint camelcase rule
render(user.email_address);O ESLint sinalizará isso como um aviso, forçando os desenvolvedores a desabilitar a regra ou converter os dados imediatamente após o recebimento.
- Dor na Desestruturação: No desenvolvimento moderno de JS/TS, a desestruturação de objetos é ubíqua. Se os campos são
snake_case, eles devem ser renomeados durante a desestruturação para evitar poluir o escopo local:
// Renomeação verbosa
const { first_name: firstName, last_name: lastName } = response.data;Isso aumenta o código boilerplate e a probabilidade de erros.
3. Mitos de Desempenho: Serialização e Transmissão de Rede
Em relação ao desempenho, existem dois mitos comuns: "A conversão de nomes de campo é muito lenta" e "Sublinhados aumentam o tamanho do payload." Vamos esclarecer com dados.
Mito 1: Overhead de Conversão em Tempo de Execução
- Linguagens Dinâmicas: Em Python ou Ruby, converter nomes de campo via substituição de regex em cada requisição consome CPU. No entanto, frameworks modernos (como Pydantic v2, reescrito em Rust) minimizam esse overhead através de mapeamentos de Schema pré-calculados.
- Linguagens Estáticas (Go/Java/Rust): Isso é efetivamente "custo zero". As tags de struct do Go (
json:"firstName") ou os caches de mapeamento do Jackson em Java são determinados em tempo de compilação ou inicialização. A execução em tempo de execução envolve uma simples cópia de bytes, não um cálculo dinâmico.
Nota: Nunca realize conversão recursiva global no frontend (thread principal do navegador) usando interceptadores (ex: Axios). Para grandes respostas, isso causa travamentos na página e desperdício de memória. Conclusão: O backend deve lidar com a conversão.
Mito 2: Tamanho de Transmissão e Compressão
Teoricamente, first_name é um byte mais longo que firstName. No entanto, com a compressão Gzip ou Brotli habilitada (configuração HTTP padrão), essa diferença praticamente desaparece.
- Princípio: Algoritmos de compressão dependem de "referenciamento de strings duplicadas". Em um array JSON, as chaves são altamente repetitivas. O algoritmo armazena
first_nameem um dicionário no primeiro encontro e substitui ocorrências subsequentes por um pequeno ponteiro. - Benchmarks: Testes mostram que sob Gzip nível 6, a diferença de tamanho entre os dois estilos é tipicamente entre 0.5% e 1%. A menos que você esteja transmitindo dados por links de satélite, isso não é um problema.
4. Experiência do Desenvolvedor (DX) e Psicologia Cognitiva
Arquitetura não é apenas sobre máquinas; é sobre pessoas.
- Legibilidade do
snake_case: A psicologia cognitiva sugere que sublinhados fornecem separação visual clara.parse_db_xmlé processado pelo cérebro mais rapidamente do queparseDbXml, especialmente ao lidar com acrônimos consecutivos (ex:XMLHTTPRequestvsXmlHttpRequest). Esta é uma das razões pelas quais a documentação da Stripe é considerada altamente legível. - Consistência do
camelCase: O estado de fluxo trazido pela consistência full-stack é mais crítico. Para equipes full-stack JS/TS, usarcamelCaseem todo o frontend e backend permite a reutilização direta de definições de tipo (Interface/Zod Schema), eliminando completamente a carga cognitiva de "tradução mental".
5. Padrões da Indústria e Racional
| Organização | Escolha | Lógica Central e Contexto |
|---|---|---|
| camelCase | O Guia de API do Google (AIP-140) exige lowerCamelCase para JSON. Mesmo que as definições internas do Protobuf usem snake_case, a camada de conversão externa muda automaticamente para camelCase para se alinhar com o ecossistema da Web. |
|
| Microsoft | camelCase | Com o .NET Core abraçando o código aberto e a invenção do TypeScript, a Microsoft pivotou totalmente para os padrões da Web, abandonando o PascalCase inicial. |
| Stripe | snake_case | Uma empresa típica da pilha Ruby. Eles mascaram a diferença fornecendo SDKs de Cliente extremamente robustos. Ao usar o SDK Node, embora snake_case seja transmitido, as assinaturas dos métodos do SDK geralmente seguem as convenções JS. |
| JSON:API | camelCase | A especificação impulsionada pela comunidade recomenda explicitamente o camelCase, refletindo o consenso da comunidade Web. |
6. Aconselhamento Arquitetônico Profundo: Desacoplamento e DTOs
Um anti-padrão comum é o "Pass-through": serializar diretamente entidades de banco de dados para retorná-las.
- Se você fizer isso, e suas colunas de DB forem
snake_case, sua API se tornasnake_case. - Risco: Isso viola o princípio de ocultação de informações, expõe estruturas de tabela e cria um forte acoplamento entre a API e o DB. Se o DB for renomeado, a API quebra.
Melhor Prática: Introduza uma camada DTO (Data Transfer Object). Independentemente de como o banco de dados subjacente é nomeado, você deve definir um contrato de API independente (DTO). Já que você está definindo um DTO, por que não defini-lo como camelCase para aderir aos padrões da Web? Ferramentas de mapeamento modernas (MapStruct, AutoMapper, Pydantic) lidam com essa conversão sem esforço.
7. Olhando para o Futuro: GraphQL e gRPC
GraphQL: A comunidade adota quase 100% o camelCase. Se sua equipe planeja introduzir o GraphQL no futuro, projetar APIs REST com camelCase agora é uma estratégia inteligente de "compatibilidade futura".
gRPC: O padrão Protobuf dita: arquivos .proto usam snake_case para definições de campo, mas eles devem ser convertidos para camelCase quando mapeados para JSON. Esta é a solução padrão do Google para ambientes multilíngues.
8. Resumo e Matriz de Decisão
Não existe certo ou errado absoluto, apenas trade-offs. Aqui está o framework de decisão final:
Recomendado: Padrão para camelCase
Para a grande maioria das APIs RESTful novas e de propósito geral que atendem a clientes Web/App, camelCase é fortemente recomendado.
Razão: Alinhar-se com o domínio de JSON/JavaScript/TypeScript, adotando os hábitos de 90% dos consumidores.
Ferramentas: Obtenha o melhor suporte de geradores de código OpenAPI, Swagger UI e IDEs modernas.
Quando usar snake_case?
1. Consumidores Específicos: Os usuários primários da API são cientistas de dados Python ou operações de sistema (Curl/Bash).
2. Sistemas Legados: As APIs existentes já são snake_case. Consistência > Melhor Prática. Não misture estilos dentro do mesmo sistema.
3. Extremismo de Velocidade no Backend: Usando Python/Ruby sem recursos para manter uma camada DTO, passando diretamente modelos de banco de dados.
Tabela de Decisão
| Dimensão | Estilo Recomendado |
|---|---|
| Frontend Web / Aplicativo Móvel | camelCase (Impedância zero, segurança de tipo) |
| Análise de Dados / Computação Científica | snake_case (Adequado para hábitos Python/R) |
| Backend Node.js / Go / Java | camelCase (Suporte nativo ou de biblioteca perfeito) |
| Backend Python / Ruby | camelCase (Conversor recomendado) ou snake_case (Apenas ferramentas internas) |
| Equipe Full-Stack | Quanto maior o grau full-stack, mais camelCase é recomendado |
A essência do design de API é a empatia. No contexto das APIs Web, encapsular a complexidade no backend (lidando com o mapeamento) e deixar a conveniência para o usuário (aderindo aos hábitos de JS) é a escolha que reflete maior profissionalismo.
