08 de nov. de 2025·8 min de leitura

Validação de entrada no servidor para APIs que rejeita dados inválidos

Validação de entrada no servidor para APIs mantém dados ruins fora. Aprenda parsing seguro, esquemas, tipos estritos e erros claros que realmente protegem produção.

Validação de entrada no servidor para APIs que rejeita dados inválidos

Por que sua API continua aceitando dados sem sentido

A maioria das APIs que “aceita qualquer coisa” foi construída para o caminho feliz. O código assume que o cliente vai enviar os campos certos, na forma certa, com os tipos certos. Então, quando chega uma requisição com campos faltando, campos a mais, strings onde deveriam ser números ou um objeto totalmente diferente, o servidor silenciosamente força tudo no lugar, continua e ainda retorna 200.

Isso é especialmente comum em endpoints gerados por IA. Muitas vezes desserializam JSON direto em objetos, pulam checagens estritas e confiam no “funcionou na demo”. O resultado é uma API que parece ok em testes rápidos, mas se comporta de forma imprevisível quando usuários reais, integrações reais ou atacantes aparecem.

Checagens no cliente não te protegem. Navegadores podem ser contornados, apps móveis podem ser modificados e clientes terceiros podem enviar qualquer payload. Mesmo clientes bem intencionados podem sair de sincronia depois de uma release e começar a enviar campos que seu servidor nunca esperou.

Em produção, validação fraca vira problemas caros:

  • Quedas e timeouts quando o código encontra um tipo inesperado ou null
  • Registros ruins que parecem válidos mas quebram relatórios e fluxos depois
  • Bugs de segurança quando entradas não confiáveis alcançam queries, caminhos de arquivos ou lógica de auth
  • Dor de depuração porque o mesmo input ruim falha de maneiras diferentes em lugares diferentes

O objetivo da validação de entrada no servidor para APIs é simples: rejeitar entradas ruins cedo, de forma consistente e segura. Isso significa um portão claro na borda da sua API que verifica forma, tipos e limites antes da lógica de negócio rodar.

Times costumam vir à FixMyMess com endpoints que “funcionam” mas aceitam lixo como e-mails vazios, quantidades negativas ou objetos onde deveria vir um ID. A correção raramente é complicada: adicione validação estrita no início para que nonsense nunca entre no sistema.

Validação, sanitização e parsing: a diferença simples

Se você quer que uma API pare de aceitar nonsense, precisa separar três tarefas que frequentemente se misturam: validação, sanitização e parsing.

Validação responde: “Essa entrada é permitida?” Verifica forma e regras: campos obrigatórios, tipos, intervalos, comprimentos, formatos e valores permitidos. Boa validação de entrada no servidor para APIs rejeita requisições ruins cedo, antes que toquem seu banco de dados, lógica de auth ou chamadas a terceiros.

Sanitização responde: “Se essa entrada é permitida, como a tornamos segura para armazenar ou exibir?” Exemplos são escapar texto antes de renderizar em HTML, remover caracteres de controle ou eliminar marcação inesperada. Sanitização não substitui validação. Uma string limpa ainda pode ser do tipo errado, muito longa ou faltar campos-chave.

Parsing (e normalização) responde: “Transformar dados desconhecidos em uma forma conhecida.” Você decodifica JSON, converte strings em números, aplica defaults e normaliza formatos (como colocar e-mail em caixa baixa). O padrão seguro é parsear e então usar. O padrão arriscado é usar e então torcer.

Um exemplo simples: um endpoint de cadastro recebe age: "25" (string), email: "[email protected] " e role: "admin". Um fluxo seguro é:

  • Parsear e normalizar: trim no e-mail, lowercase, converter age para número
  • Validar: age deve ser 13-120, role deve estar entre os valores permitidos
  • Só então: criar o usuário

Esse “contrato de entrada estrito” (um esquema com tipos e limites claros) é o baseline. Não evita todo ataque por si só, mas bloqueia lixo acidental, reduz bugs de borda e facilita fazer checagens de segurança corretamente.

Formas comuns como validação fraca quebra sistemas reais

Validação fraca raramente falha de forma limpa. Normalmente ela “funciona” em testes, depois quebra sob tráfego real porque usuários reais, bots e clientes bugados enviam entradas esquisitas.

Uma falha comum é over-posting. Um cliente envia campos extras que você nunca planejou, e seu código acidentalmente usa ou armazena esses campos porque espalha todo o corpo da requisição em uma escrita no banco. Isso pode alterar flags como isAdmin, mudar campos de preço ou sobrescrever configurações internas sem que ninguém perceba.

Outra é confusão de tipos. Se você espera um número mas aceita uma string, surgem surpresas: "10" vira 10 em um lugar, continua string em outro, e de repente ordenação, comparações e cálculos ficam errados. Pior, "", "NaN" ou "001" podem passar e criar casos de borda difíceis de depurar.

Limites são onde o código do “caminho feliz” colapsa. Sem checagens de tamanho, uma única requisição pode enviar uma string de 5 MB, um array de 50.000 itens ou JSON profundamente aninhado que consome CPU e memória. A API pode não cair toda vez, mas fica lenta, dá timeout e causa falhas em cascata.

Problemas de segurança acontecem quando você confia na entrada cedo demais. Se dados não validados são usados em queries SQL, filtros, caminhos de arquivos ou output HTML, você abre portas para injeção e vazamento de dados.

Aqui estão padrões que aparecem repetidamente quando falta validação de entrada no servidor para APIs:

  • Escrever campos “desconhecidos” no banco porque o payload não é whitelistado
  • Coerção implícita de tipos e então tomar decisões com valores errados
  • Permitir strings/arrays sem limites, levando a lentidão e outages
  • Passar input cru para queries ou templates antes de checar e parsear

FixMyMess frequentemente vê esses problemas em endpoints gerados por IA: parecem limpos, mas aceitam quase qualquer JSON e torcem para que o código downstream lide com isso. Sistemas reais precisam do oposto: rejeitar nonsense cedo, claramente e de forma consistente.

Escolha um approach de esquema que se encaixe na sua stack

O objetivo da validação de entrada no servidor para APIs é simples: cada requisição é checada contra um contrato claro antes de tocar sua lógica de negócio. A forma mais fácil de fazer isso é usar um esquema que possa tanto validar quanto parsear com segurança as entradas nos tipos que seu código espera.

Se você está em JavaScript ou TypeScript, bibliotecas de esquema como Zod ou Joi são populares porque podem coagir tipos cuidadosamente (quando você permitir) e dão erros legíveis. Se estiver em Python, Pydantic é uma escolha comum porque transforma dados recebidos em modelos estritos com defaults. Se você já usa um workflow OpenAPI-first ou JSON Schema, manter JSON Schema pode manter sua documentação e validação alinhadas. Muitos frameworks também têm validadores embutidos, que podem ser suficientes para APIs menores.

Onde executar a validação importa. Dois padrões comuns são:

  • Middleware que valida body, query e params antes do handler rodar
  • Validação dentro de cada route handler, perto do código que usa os dados

Middleware é mais fácil de manter consistente. Validação por handler pode ser mais clara quando cada rota tem regras especiais. De qualquer modo, tente fazer do esquema a única fonte de verdade para corpo, query strings e path params, para não acabar validando o body e esquecendo os params.

Um exemplo prático: um endpoint espera limit (número) na query e email (string) no body. Sem um esquema, código gerado por IA frequentemente aceita limit="ten" ou email=[] e falha depois de maneiras confusas. Com um esquema, isso é rejeitado imediatamente com um erro limpo.

Finalmente, planeje mudanças. Quando seu contrato de API evoluir, version suas schemas da mesma forma que versiona endpoints ou clientes. Mantenha schemas antigos para clientes antigos e introduza novos com um corte claro. Isso é uma correção comum que vemos na FixMyMess quando times herdam protótipos rápidos gerados por IA e precisam torná-los seguros sem reescrever tudo.

Passo a passo: adicione validação no servidor a um endpoint

Escolha um endpoint que causa dor, como POST /users ou POST /checkout. O objetivo é validação de entrada no servidor para APIs que rejeita nonsense antes da lógica de negócio rodar.

1) Defina um esquema pequeno (apenas o que precisa)

Comece apenas com campos obrigatórios. Se o endpoint cria um usuário, talvez você realmente precise só de email e password, não de 12 campos opcionais “só por via das dúvidas”. Mantenha o esquema estrito e explícito.

Valide cada fonte de entrada separadamente: path params, query params e body. Trate-os como buckets diferentes com riscos diferentes.

// Pseudocode schema
const bodySchema = {
  email: { type: "email", required: true, maxLen: 254 },
  password: { type: "string", required: true, minLen: 12, maxLen: 72 }
};
const querySchema = { invite: { type: "string", required: false, maxLen: 64 } };
const pathSchema = { orgId: { type: "uuid", required: true } };

2) Validar + parsear antes de qualquer outra coisa

Faça da validação as primeiras linhas do handler. Não “conserte” tipos aleatoriamente depois.

  • Parseie body, query e path separadamente em valores tipados
  • Rejeite campos desconhecidos (modo estrito) para que chaves extras não escapem
  • Adicione limites: min/max, limites de comprimento e checagens de formato simples

Um exemplo concreto: se alguém envia { "email": [], "password": true, "role": "admin" }, parsing estrito deve rejeitar. Não deve coagir tipos, e definitivamente não deve aceitar role se o seu esquema não permitir.

3) Adicione testes para entradas inválidas

Um bom teste inválido vale por dez testes do caminho feliz. Tente campos faltando, tipos errados, campos extras, strings gigantes, números negativos e codificações estranhas. É justamente onde endpoints gerados por IA falham, e é o tipo de correção que times trazem à FixMyMess quando um protótipo entra em produção.

Padrões de parsing seguro que mantêm bugs fora

Rebuild clean from scratch
Quando consertar vira bagunça, podemos reconstruir o backend em cerca de 24 horas.

A maioria dos bugs não é causada por “falta de validação”, mas pelo que acontece depois da validação. O hábito mais seguro é parsear a entrada uma vez, obter sucesso ou falha claro, e então trabalhar apenas com o resultado parseado.

Parseie primeiro e esqueça a requisição crua

Uma boa biblioteca de esquema oferece uma API de “safe parse”: retorna ou um valor parseado confiável ou um erro que você pode devolver ao cliente. Isso é o núcleo da validação de entrada no servidor para APIs.

// Example shape, works similarly in many schema libraries
const result = UserCreateSchema.safeParse(req.body);
if (!result.success) {
  return res.status(400).json({ error: "Invalid input", fields: result.error.fields });
}

const input = result.data; // only use this from now on
// Never touch req.body again in this handler
createUser({ email: input.email, age: input.age });

Essa única mudança previne um bug comum em endpoints gerados por IA: o código valida, mas depois lê de req.body de novo e acaba aceitando campos extras, tipos errados ou casos de borda esquisitos.

Normalize apenas quando for intencional

Normalização pode ajudar, mas deve ser uma escolha deliberada, não um acidente.

  • Faça trim em strings apenas para campos onde espaços nunca fazem sentido (emails, usernames).
  • Escolha uma regra de caixa quando comparações importarem (por exemplo, emails em lowercase).
  • Converta datas de string para objetos Date apenas se seu esquema garante o formato.
  • Mantenha IDs exatos; não auto-trime nem modifique a menos que o sistema já force isso.

Evite “coerção mágica”

Tenha cuidado com coersão como transformar "123" em 123. Isso esconde entradas ruins e dificulta detectar bugs de cliente ou abuso. Coaja apenas quando realmente precisa (como query params que são sempre strings) e, quando fizer, imponha limites (min, max, apenas inteiros) para não aceitar nonsense como "999999999999".

Se você herdou uma API gerada por IA que “funciona” mas aceita lixo, esse padrão de parsear-antes-de-usar-o-resultado-parseado é uma das correções mais rápidas e seguras.

Tipos estritos, defaults e limites que importam

Validação estrita não é só sobre “o campo está presente”. É sobre fazer sua API aceitar apenas as formas e valores que você está disposto a suportar. Boa validação de entrada no servidor para APIs começa na fronteira: body da requisição, query string e headers.

Defaults pertencem à borda

Defina defaults durante o parsing, não no meio da sua lógica de negócio. Assim, tudo depois da borda pode assumir uma forma completa e conhecida.

Exemplo: se page está ausente, defina como 1 durante o parsing. Não deixe partes aleatórias do código decidirem depois, porque você acabará com comportamentos diferentes em endpoints diferentes.

Também decida o que “ausente” significa. Um campo ausente não é o mesmo que um campo null.

  • Opcional: o cliente pode omiti-lo (ex: middleName não fornecido).
  • Nulável: o cliente pode enviar null (ex: deletedAt: null quando não deletado).

Trate esses casos de forma diferente no seu esquema. Caso contrário você terá bugs estranhos como null passando na validação mas quebrando código que espera uma string.

Enums e limites evitam classes inteiras de bugs

Se você conhece os valores permitidos, declare-os. Enums impedem strings “quase certas” (como adminn) de entrarem e criarem estados ocultos.

Um exemplo realista: um endpoint gerado por IA pega status e sort de query params. Sem tipos estritos, status=donee pode ser tratado como truthy e retornar registros errados, e sort=DROP TABLE pode ser concatenado numa query.

Adicione limites que protejam seu banco e sua fatura:

  • Limite limit (por exemplo, max 100)
  • Trave page para >= 1
  • Allowlist de campos sortBy (ex: createdAt, name)
  • Restrinja order para asc ou desc
  • Defina comprimentos máximos para strings (nomes, emails, termos de busca)

Essas são correções comuns que aplicamos ao reparar protótipos gerados por IA na FixMyMess, porque código do “caminho feliz” frequentemente aceita qualquer coisa e só falha em produção quando usuários reais mandam caos.

Respostas de erro úteis sem exagerar

Rescue an AI prototype
Perfeito para agências que herdam apps gerados por IA que quebram com tráfego real.

Quando a entrada está errada, sua API deve ser clara e entediante: retorne 400, explique o que corrigir e mantenha a forma da resposta a mesma sempre. Uma forma estável ajuda clientes a lidarem com erros sem casos especiais e evita que seu time vaze detalhes depois.

Um padrão simples é um envelope de erro mais detalhes por campo:

{
  "error": {
    "code": "INVALID_INPUT",
    "message": "Some fields are invalid.",
    "fields": [
      { "path": "email", "message": "Must be a valid email address." },
      { "path": "age", "message": "Must be an integer between 13 and 120." }
    ]
  }
}

Mantenha as mensagens focadas no que o chamador pode mudar. Evite ecoar o input cru (especialmente strings que possam conter HTML ou SQL) e nunca inclua stack traces, erros SQL, IDs internos ou nomes de bibliotecas. Em vez de "ZodError: Expected number, received string", diga "age must be a number".

Bibliotecas de esquema frequentemente dão erros detalhados. Mapeie-os para seu formato de API e mantenha os caminhos de campo previsíveis (caminhos dot funcionam bem). Se houver muitos problemas, limite o número retornado (por exemplo, os primeiros 10) para que a resposta permaneça pequena.

Para depuração própria, logue falhas de validação com segurança. Registre:

  • id da requisição e endpoint
  • caminhos de campo que falharam (não valores crus)
  • metadados do chamador que você já confia (user ID, tenant)
  • um snapshot redigido do payload

Isso é uma correção comum em código de API gerado por IA: a UI recebe feedback amigável, enquanto seus logs ainda explicam por que requisições foram rejeitadas, sem expor segredos.

Armadilhas comuns ao adicionar validação

O maior erro é validar tarde demais. Se você lê campos, monta uma query SQL ou escreve em storage e só então checa os valores, o dano já foi feito. Validação precisa acontecer na borda: parsear, validar e só então tocar o resto do seu código.

Outra armadilha é confiar em tipos que existem apenas em tempo de compilação. Código escrito por IA costuma parecer “tipado” mas ainda aceita qualquer coisa em runtime. Uma anotação UserId: string não impede "", " " ou "DROP TABLE" de chegar. Validação no servidor tem que rodar em cada requisição, não só no seu editor.

“Permitir campos desconhecidos por flexibilidade” também costuma dar errado. Campos extras viram esconderijo para bugs, clientes confusos e problemas de segurança (como um role: "admin" escapando para seu objeto de usuário). Se precisar de compatibilidade futura, aceite só campos conhecidos e version sua API quando a forma mudar.

Frameworks podem sabotar sua intenção coisificando tipos silenciosamente. Se "false" vira true, ou "123abc" vira 123, você vai liberar bugs lógicos difíceis de reproduzir. Prefira parsing estrito que falha rápido com erro claro.

Por fim, muitos times esquecem limites, então a validação passa mas seu servidor ainda sofre. Algumas proteções básicas evitam abuso e acidentes:

  • Cap tamanho do body e rejeite payloads oversized cedo.
  • Defina comprimentos máximos para strings (nomes, emails, IDs).
  • Limite arrays (itens por requisição) e profundidade de aninhamento de objetos.
  • Exija formatos explícitos (UUIDs, datas ISO) e rejeite “quase certo”.
  • Mantenha defaults intencionais; não preencha campos ausentes de formas que escondam bugs do cliente.

Um exemplo prático: um endpoint gerado por IA que “atualiza perfil” pode aceitar uma bio de 5MB, um objeto aninhado onde se esperava uma string e chaves desconhecidas que sobrescrevem dados armazenados. Esse é o tipo de limpeza que a FixMyMess costuma encontrar em auditorias: existe validação, mas ela é permissiva nos lugares errados.

Checklist rápido para entradas de API mais seguras

Se você quer validação de entrada no servidor para APIs que realmente bloqueie dados ruins, mantenha um checklist curto e aplique a cada endpoint que tocar. A maioria dos bugs “funciona na minha máquina” vem de pular um desses básicos.

Comece validando toda superfície de entrada, não apenas bodies JSON. Query strings e route params também são não confiáveis e frequentemente controlam filtros, IDs e paginação.

Use este checklist como seu mínimo:

  • Valide body, query e params antes de qualquer lógica de negócio ou chamadas ao banco.
  • Prefira allowlists: rejeite campos desconhecidos a menos que precise explicitamente de payloads flexíveis.
  • Coloque limites rígidos em todo lugar: tamanho máximo de string, intervalos numéricos, tamanhos de array e limites de paginação.
  • Parseie para um objeto tipado e validado e use apenas esse output parseado. Se parsing falhar, falhe fechado.
  • Adicione alguns casos de teste cruéis por endpoint, incluindo tipos errados, campos obrigatórios faltando, campos extras e inputs oversized.

Um exemplo rápido: seu endpoint espera { "email": "...", "age": 18 }. Uma requisição real pode enviar age: "18", age: -1 ou adicionar "isAdmin": true. Se você coage tipos silenciosamente ou aceita chaves extras, está treinando seu sistema a aceitar nonsense e, pior, mudanças de privilégio.

Se você herdou código de API gerado por IA, esse checklist é onde as correções geralmente começam. Times que trabalham com a FixMyMess normalmente veem o mesmo padrão: o caminho feliz funciona, mas o servidor confia em qualquer coisa que aparece. Validação rígida mais parsing estrito é uma das formas mais rápidas de transformar um protótipo frágil em algo que você pode rodar em produção com segurança.

Exemplo: consertando um endpoint gerado por IA que aceita lixo

Close security holes early
Endurecemos endpoints contra caminhos de injeção e fluxos de entrada inseguros comuns em código gerado por IA.

Uma história comum: uma ferramenta de IA gera um endpoint /signup que "funciona localmente" porque você só tentou o caminho feliz. Em produção, começa a aceitar nonsense e o dano é silencioso.

Aqui vai um padrão real de falha. O endpoint espera:

  • email (string)
  • password (string)
  • plan ("starter" | "pro")

Mas a API aceita felizmente este payload:

{ "email": ["[email protected]"], "password": true, "plan": "pro ", "coupon": {"code":"FREE"} }

O que acontece depois é uma bagunça: o email vira "[email protected]" (array stringificado), a senha booleana é coagiada, o plan tem espaço final então a precificação cai para um default, e o objeto coupon inesperado pode ser armazenado como "[object Object]" ou travar um job posterior. Você vê auth quebrado, cobrança errada e linhas corrompidas difíceis de limpar.

A correção não é “sanitizar tudo”. É validação de entrada no servidor para APIs com parsing estrito.

Passo a passo da correção

Defina um esquema que rejeite campos desconhecidos, faça trim e normalize strings e force tipos. Depois parseie antes de qualquer trabalho.

  • Valide campos obrigatórios e tipos (sem coerção por padrão)
  • Normalize valores seguros (trim em plan, lowercase em email)
  • Rejeite extras (falhe ou descarte coupon)
  • Aplique limites (comprimentos máximos, regras de senha)

Quando parsing falhar, retorne um 400 claro:

"Invalid request: plan must be one of starter, pro; email must be a string; unexpected field coupon"

Resultado final: menos incidentes em produção, dados mais limpos e depuração mais rápida porque entradas ruins param na porta. Se você herdou um endpoint desses, a FixMyMess costuma achar esses pontos fracos numa auditoria rápida e corrigi-los sem reescrever o app inteiro.

Próximos passos: melhorar segurança sem reescrever tudo

Se você quer que validação de entrada no servidor para APIs dê resultado rápido, não comece por “validar tudo”. Comece onde entradas ruins causam dano real: endpoints que escrevem dados ou disparam trabalho caro.

Escolha três endpoints primeiro. Um bom conjunto é login ou signup (auth), qualquer coisa que lide com dinheiro (pagamentos) e qualquer ação administrativa. Adicione validação na borda (body da requisição, query, headers) antes de tocar seu banco, arquivos, filas ou APIs de terceiros. Esse único movimento evita a maioria dos bugs de “aceitar nonsense”.

Um plano de rollout simples que evita reescrita:

  • Adicione um esquema por endpoint e rejeite campos desconhecidos por padrão.
  • Defina limites rígidos (tamanho de string, tamanho de array, intervalos numéricos, tamanho máximo de página).
  • Normalize e parseie uma vez (trim, parsing de datas, coerção de número apenas quando intencional).
  • Adicione monitoramento para falhas de validação para ver o que os clientes estão enviando.

Clientes legados são a parte complicada. Se não puder quebrá-los de um dia para o outro, permita tolerância temporária de forma controlada: aceite a forma antiga, converta-a para a forma nova internamente e logue cada vez que tiver que “resgatar” a entrada. Coloque uma data de depreciação explícita para que isso não vire permanente.

Se sua API foi gerada por uma ferramenta de IA e o código já parece emaranhado (handlers copiados, tipos inconsistentes, bugs de auth escondidos), uma auditoria focada costuma ser mais rápida do que consertar endpoint por endpoint. FixMyMess pode fazer uma auditoria de código gratuita e depois reparar os caminhos de maior risco (validação, auth, segredos e problemas de segurança) para que você chegue a um estado “seguro por padrão” sem reconstruir tudo.