Como validar entradas e regras de negócio
Organize verificações de presença, formato, significado e regras do domínio antes que dados inadequados produzam efeitos.

Validar é decidir se um dado pode entrar no fluxo
Uma entrada chega ao algoritmo como uma afirmação ainda não comprovada. Ela pode estar ausente, ter formato incorreto, representar um valor impossível ou contrariar uma regra do negócio. Validar é verificar essas condições antes de permitir que o processamento produza efeitos.
Considere uma solicitação de compra com estes dados:
produtoId <- "P-104"
quantidadeTexto <- "3"
formaPagamento <- "pix"
Antes de reservar estoque ou cobrar, o algoritmo precisa responder:
- os campos obrigatórios foram enviados?
quantidadeTextopode ser convertido em número inteiro?- a quantidade é maior que zero e respeita o limite aceito?
formaPagamentopertence às opções permitidas?- o produto existe, está ativo e possui estoque suficiente?
Cada pergunta elimina uma classe de problema. Somente uma entrada aprovada em todas as etapas pode alcançar as ações da compra.
Validar cedo reduz estados inválidos e torna a causa do erro mais próxima da entrada que o provocou. Isso não significa misturar todas as verificações em uma única expressão; uma sequência explícita costuma ser mais fácil de explicar, testar e manter.
Toda entrada externa precisa ser tratada como não confiável
Dados não chegam apenas de formulários. Também podem vir de:
- arquivos e planilhas;
- parâmetros de URL e requisições de API;
- filas e eventos;
- sensores e dispositivos;
- bancos de dados antigos;
- integrações com parceiros;
- argumentos de linha de comando.
Uma lista suspensa no navegador pode oferecer somente pix, cartao e boleto, mas uma requisição pode ser criada fora daquela interface e enviar qualquer texto. Por isso, controles no cliente melhoram a experiência, porém não substituem a validação no componente que recebe e executa a operação.
O princípio é simples: a aparência de controle na origem não prova que o dado recebido obedece ao contrato.
Separe presença, sintaxe, significado e negócio
Organizar a validação em camadas ajuda a localizar a falha:
| Camada | Pergunta | Exemplo de falha |
|---|---|---|
| Presença | O dado obrigatório existe? | quantidade vazia |
| Sintaxe e tipo | O dado possui estrutura interpretável? | "três" não é inteiro |
| Semântica | O valor faz sentido no contexto? | quantidade -2 |
| Regra de negócio | A operação é permitida agora? | quantidade maior que o estoque |
A fronteira entre semântica e regra de negócio pode variar conforme o sistema. “Quantidade máxima de 10” pode ser uma restrição do contrato em um produto e uma política comercial em outro. O essencial é registrar qual regra está sendo aplicada, de quais dados depende e quem deve mantê-la.
Essa separação também evita mensagens imprecisas. Dizer “quantidade inválida” esconde se o campo estava vazio, não era numérico, estava fora da faixa ou excedia o estoque.
Converta com falha explícita antes de comparar
Uma entrada textual não se transforma em número apenas porque será usada em um cálculo. Faça a conversão e trate o resultado:
SE quantidadeTexto está vazia ENTÃO
retornar erro "Informe a quantidade"
FIM SE
conversao <- tentar converter quantidadeTexto para inteiro
SE conversao falhou ENTÃO
retornar erro "A quantidade deve ser um número inteiro"
FIM SE
quantidade <- conversao.valor
Somente depois compare:
SE quantidade < 1 OU quantidade > 10 ENTÃO
retornar erro "A quantidade deve estar entre 1 e 10"
FIM SE
Isso preserva a diferença entre não conseguir interpretar e interpretar um valor que está fora do intervalo. A aula sobre conversão de tipos aprofunda parsing, falhas e perdas.
Em C#, APIs como TryParse tornam o insucesso observável sem usar exceções para uma entrada inválida esperada:
if (!int.TryParse(quantidadeTexto, out int quantidade))
{
return Erro("A quantidade deve ser um número inteiro");
}
Outras linguagens usam resultados, valores opcionais ou exceções. Independentemente da forma, nunca continue com um valor padrão como 0 sem distinguir se ele veio da entrada ou foi criado após uma falha.
Prefira declarar o que é aceito
Para conjuntos pequenos, valide contra uma lista de valores permitidos:
formasPermitidas <- ["pix", "cartao", "boleto"]
SE formaPagamento NÃO PERTENCE A formasPermitidas ENTÃO
retornar erro "Forma de pagamento não aceita"
FIM SE
Essa abordagem de lista de permissão (allowlist) define o domínio válido. Tentar bloquear apenas valores conhecidos como ruins deixa espaço para formas inesperadas que a lista de bloqueio nunca previu.
Use restrições adequadas ao campo:
- valores enumerados para categorias e estados;
- mínimo e máximo para números, datas e tamanhos;
- comprimento máximo para textos;
- parser específico para datas, números e identificadores estruturados;
- expressão regular somente quando ela descreve toda a estrutura necessária.
Não torne texto livre artificialmente restrito. Nomes, endereços e comentários legítimos podem conter acentos, apóstrofos e diferentes alfabetos. A regra deve nascer do significado do campo, não de uma lista genérica de caracteres “suspeitos”.
Normalizar, validar e sanitizar não são a mesma coisa
Normalização produz uma representação consistente quando essa transformação é permitida pelo contrato. Por exemplo, remover espaços externos de um código ou transformar uma opção enumerada em minúsculas antes de compará-la.
formaPagamento <- minusculas(removerEspacosExternos(formaPagamento))
validar formaPagamento
Normalize antes de validar quando o formato canônico faz parte da regra. Não altere silenciosamente dados cujo conteúdo exato importa, como senhas, assinaturas digitais ou identificadores sensíveis a maiúsculas e minúsculas.
Sanitização tenta tornar um conteúdo seguro para um uso específico. Ela não substitui a validação e também não substitui proteções próprias do destino, como consultas parametrizadas em banco ou codificação de saída em HTML. Um valor pode ser válido para armazenamento e ainda precisar de tratamento adequado quando for exibido ou enviado a outro interpretador.
Regras de negócio dependem do estado e da operação
Depois de interpretar os campos, o algoritmo ainda precisa saber se a compra é permitida:
produto <- buscar produto por produtoId
SE produto não existe ENTÃO
retornar erro "Produto não encontrado"
FIM SE
SE NÃO produto.ativo ENTÃO
retornar erro "Produto indisponível"
FIM SE
SE quantidade > produto.estoqueDisponivel ENTÃO
retornar erro "Quantidade maior que o estoque disponível"
FIM SE
Essas verificações não tratam apenas formato. Elas protegem invariantes: condições que precisam permanecer verdadeiras durante as mudanças de estado. Um item de pedido, por exemplo, não deveria existir com quantidade negativa; uma reserva confirmada não deveria superar o estoque realmente concedido.
Mantenha regras essenciais próximas da operação que protege o estado. Validar apenas na tela permite que outra interface, integração ou rotina interna ignore a mesma política.
Também diferencie validação de autorização. Uma quantidade pode ser perfeitamente válida e, ainda assim, a pessoa não ter permissão para comprar em nome daquela organização. O sistema precisa das duas decisões; aprovação em uma não implica aprovação na outra.
Validação anterior não garante um estado futuro
Imagine dois pedidos consultando o último item em estoque ao mesmo tempo. Ambos podem observar estoqueDisponivel = 1 e passar pela validação. Se as duas confirmações ocorrerem sem coordenação, o estoque ficará inconsistente.
Isso é uma disputa entre o momento da verificação e o momento da alteração. A validação melhora o fluxo, mas regras dependentes de estado também precisam ser garantidas na operação final, com os mecanismos de consistência adequados ao sistema.
Em um algoritmo conceitual, torne essa unidade visível:
iniciar operação de reserva
conferir estoque atual
SE quantidade disponível ENTÃO
reduzir estoque
confirmar reserva
SENÃO
rejeitar compra
FIM SE
finalizar operação de reserva
Não use uma consulta antiga como prova permanente. Quanto mais mutável for o dado, mais perto da alteração a regra precisa ser confirmada.
Escolha entre parar cedo e acumular erros
Há duas estratégias válidas para tratar falhas.
Parar na primeira falha
É útil quando uma etapa depende da anterior ou quando continuar seria inseguro:
SE quantidade não pode ser convertida ENTÃO
retornar erro de formato
FIM SE
SE quantidade está fora da faixa ENTÃO
retornar erro de intervalo
FIM SE
Não existe motivo para testar a faixa antes de possuir um número confiável.
Acumular falhas independentes
Em um formulário, pode ser melhor informar de uma vez que nome, data e quantidade precisam de correção:
erros <- lista vazia
SE nome está vazio ENTÃO
adicionar "Informe o nome" em erros
FIM SE
SE data possui formato inválido ENTÃO
adicionar "Informe uma data válida" em erros
FIM SE
SE quantidade não é inteira ENTÃO
adicionar "Informe uma quantidade inteira" em erros
FIM SE
SE erros não está vazia ENTÃO
retornar erros
FIM SE
Acumule somente verificações independentes. Regras que exigem conversão, consulta ou autorização bem-sucedida devem aguardar seus pré-requisitos.
Cliente, aplicação e domínio têm papéis diferentes
Em uma aplicação web, a mesma restrição pode aparecer em mais de um ponto por razões distintas:
- cliente: oferece retorno rápido e orienta a correção;
- servidor ou aplicação: protege a fronteira confiável e interpreta o contrato recebido;
- domínio: impede que operações deixem entidades em estados proibidos;
- armazenamento: reforça restrições estruturais que ele é capaz de garantir.
Isso não autoriza copiar toda regra para todos os lugares. Uma validação simples no cliente pode espelhar uma regra para melhorar a experiência, mas a fonte confiável continua no servidor ou no domínio. Centralize definições quando a tecnologia permitir e teste se as camadas permanecem coerentes.
Mensagens devem permitir correção sem expor o sistema
Uma mensagem útil informa o campo e a condição esperada:
- fraca: “Dados inválidos”;
- útil: “A quantidade deve ser um número inteiro entre 1 e 10”.
Preserve também um identificador estável de erro quando outras partes do sistema precisarem reagir:
codigo <- "QUANTIDADE_FORA_DA_FAIXA"
mensagem <- "A quantidade deve estar entre 1 e 10"
campo <- "quantidade"
Não devolva detalhes internos, consultas, caminhos de arquivos ou segredos. Para autenticação e informações sensíveis, mensagens específicas demais podem revelar dados que uma pessoa não deveria descobrir. Clareza para correção e proteção de informação precisam coexistir.
Teste cada fronteira e cada dependência
Para a quantidade permitida entre 1 e 10, uma matriz mínima inclui:
| Entrada bruta | Resultado esperado |
|---|---|
| ausente | erro de obrigatoriedade |
"abc" | erro de formato |
"1.5" | erro: precisa ser inteira |
"0" | erro de limite inferior |
"1" | válida |
"10" | válida |
"11" | erro de limite superior |
Depois combine uma entrada estruturalmente válida com estados diferentes:
| Produto | Estoque | Quantidade | Resultado |
|---|---|---|---|
| inexistente | — | 2 | produto não encontrado |
| inativo | 8 | 2 | produto indisponível |
| ativo | 1 | 2 | estoque insuficiente |
| ativo | 2 | 2 | compra permitida |
Use o teste manual do algoritmo para registrar onde cada caso para. Inclua limites imediatamente antes, no ponto exato e imediatamente depois. Teste também valores permitidos, pois uma validação que rejeita tudo continua incorreta.
Erros comuns
Validar somente o caminho feliz
Confirmar "3" não revela o comportamento para vazio, texto, zero, limite e valor excessivo.
Comparar antes de converter
Comparações entre texto e número podem falhar ou produzir coerções inesperadas. Interprete o dado e trate a falha primeiro.
Confiar no formulário ou na lista suspensa
O cliente pode ser contornado. A fronteira que executa a operação precisa validar novamente.
Bloquear exemplos ruins em vez de definir o domínio válido
Listas de bloqueio são incompletas. Prefira valores, estruturas, tamanhos e faixas permitidos.
Alterar silenciosamente a intenção
Trocar uma quantidade negativa por zero ou uma data inválida pela data atual esconde a falha. Corrija automaticamente apenas quando o contrato declarar essa transformação.
Misturar validação, autorização e proteção de saída
São controles complementares. Um dado válido não é automaticamente autorizado nem seguro em qualquer destino.
Validar uma vez e confiar para sempre
Estoque, saldo, prazo e estado podem mudar. Reconfirme invariantes no momento da alteração.
Pratique com uma reserva de sala
Uma solicitação contém dataTexto, horaInicio, horaFim e quantidadePessoas. A sala aceita de 1 a 12 pessoas e não pode receber reservas sobrepostas.
Construa o algoritmo em etapas:
- verifique campos obrigatórios;
- converta data, horas e quantidade;
- confirme que o início ocorre antes do fim;
- valide a faixa de capacidade;
- verifique se a sala está ativa e livre naquele intervalo;
- somente então registre a reserva.
Crie casos para campo vazio, data impossível, horários iguais, 0, 1, 12 e 13 pessoas, sala inativa, conflito de horário e reserva válida. Classifique cada falha como presença, sintaxe, semântica ou regra de negócio.
O que você deve guardar
Validação é uma sequência de decisões que impede dados inadequados de alcançar efeitos importantes. Comece por presença e formato, avance para significado e regras do domínio e mantenha cada dependência explícita.
Defina o que é aceito, trate conversões sem esconder falhas, use o cliente para orientar e o servidor para confiar, preserve invariantes perto das operações e teste limites e estados mutáveis. Com isso, encerramos as estruturas de decisão; agora veja o que são estruturas de repetição e como condições passam a controlar várias iterações.
Referências
- OWASP Cheat Sheet Series — Input Validation. Acesso em 10 set. 2026.
- MDN Web Docs — Using HTML form validation and the Constraint Validation API. Acesso em 10 set. 2026.
- Microsoft Learn — Designing validations in the domain model layer. Acesso em 10 set. 2026.
- Microsoft Learn — Type conversions, casting, and boxing. Acesso em 10 set. 2026.