Quem desenvolve APIs em Delphi utilizando o framework Horse sabe o quanto ele é leve, rápido e extremamente eficiente. No entanto, à medida que a aplicação cresce, começamos a nos deparar com um problema comum em nossos controllers: o excesso de código repetitivo (o famoso boilerplate) para ler payloads de requisições e validar os dados de entrada.
Se você se cansa de escrever dezenas de linhas checando se campos obrigatórios foram preenchidos, se e-mails são válidos ou se um valor numérico está no intervalo correto, você precisa conhecer o horse-dto.
Neste artigo, vamos entender como esse middleware automatiza o processo de desserialização e validação declarativa de dados usando atributos no Delphi.
O Problema: O Excesso de Boilerplate nos Controllers
Tipicamente, ao criar um endpoint de cadastro, seu controller precisa realizar os seguintes passos:
- Obter o corpo da requisição (geralmente um JSON).
- Instanciar uma classe de domínio ou de transferência de dados (DTO).
- Fazer o parse do JSON para a classe manualmente ou via Serializers.
- Validar campo por campo (ex:
if Nome = '' then Error...). - Liberar a memória em blocos
try..finally.
Essa abordagem polui o controller, violando o princípio de Responsabilidade Única (SRP) do SOLID, já que seu controller acaba fazendo mais do que simplesmente orquestrar a requisição e a resposta.
A Solução: Horse DTO & Validation Middleware
O horse-dto é uma biblioteca que introduz o conceito de validação declarativa baseada em atributos e auto-binding (vinculação automática de dados). Com ele, você define as regras de validação diretamente na sua classe DTO através de atributos e deixa que o middleware faça toda a desserialização e consistência dos dados de forma automática.
Passo a Passo Prático de Implementação
1. Instalação
Adicionar a dependência ao seu projeto Delphi é extremamente simples utilizando o gerenciador de pacotes Boss. No terminal da pasta do seu projeto, execute:
boss install horse-dto
2. Declarando o DTO com Atributos de Validação
Em vez de validar seus dados programaticamente, você passa a decorá-los de forma elegante. Veja o exemplo de um DTO de cadastro de usuário:
unit DTO.Usuario;
interface
uses
Horse.DTO;
type
TUsuarioCadastroDTO = class
private
FNome: string;
FEmail: string;
FIdade: Integer;
public
[Required('O nome é obrigatório')]
[MinLength(3, 'O nome deve ter no mínimo 3 caracteres')]
property Nome: string read FNome write FNome;
[Required('O e-mail é obrigatório')]
[Email('E-mail em formato inválido')]
property Email: string read FEmail write FEmail;
[Range(18, 120, 'O usuário deve ter entre 18 e 120 anos')]
property Idade: Integer read FIdade write FIdade;
end;
implementation
end.
3. Registrando o Middleware na Rota
Agora, basta informar ao Horse que você deseja utilizar o middleware genérico THorseDTO<T>.AsMiddleware() ao registrar a rota. O middleware intercepta a requisição, valida os dados e injeta o objeto já preenchido diretamente no corpo da requisição:
uses
Horse,
Horse.DTO,
DTO.Usuario;
procedure CadastrarUsuario(Req: THorseRequest; Res: THorseResponse);
var
LInput: TUsuarioCadastroDTO;
begin
// O objeto já vem validado e instanciado pelo middleware!
LInput := Req.Body<TUsuarioCadastroDTO>;
// Processe seus dados com total segurança.
// Observação: O ciclo de vida da memória do objeto é controlado automaticamente pelo middleware!
Res.Send('Usuário ' + LInput.Nome + ' cadastrado com sucesso!');
end;
begin
// Registra o middleware na rota POST
THorse.Post('/usuarios', [THorseDTO<TUsuarioCadastroDTO>.AsMiddleware()], CadastrarUsuario);
THorse.Listen(9000);
end.
Como o Middleware trata as inconsistências?
Se o cliente da sua API enviar dados inconsistentes, como uma idade abaixo de 18 anos ou um e-mail mal formatado, o middleware interrompe o fluxo imediatamente. Ele responde automaticamente ao cliente com o código HTTP 400 Bad Request e envia um JSON estruturado com a lista de erros:
{
"error": "Erro de validação de DTO",
"errors": [
{
"field": "Email",
"message": "E-mail em formato inválido"
},
{
"field": "Idade",
"message": "O usuário deve ter entre 18 e 120 anos"
}
]
}
Isso garante que seu controller só receba dados 100% íntegros e reduz dezenas de tratativas manuais de erro.
Atributos de Validação Prontos para Uso
O pacote traz diversos atributos integrados de fábrica para facilitar seu desenvolvimento diário:
- [Required]: Garante que a propriedade foi enviada e não está vazia.
- [MinLength] e [MaxLength]: Controlam o limite de caracteres para strings.
- [Range]: Define limites numéricos mínimos e máximos (para Integers e Floats).
- [Email]: Valida se o formato do e-mail é legítimo via RegEx.
- [Pattern]: Permite que você informe uma Expressão Regular customizada para validação.
- [CustomValidator]: Para validações complexas e regras de negócio personalizadas.
Estendendo com Validações Personalizadas (Custom Validator)
Há casos em que precisamos ir além do formato e checar regras de negócio complexas, como validar um CPF/CNPJ ou verificar no banco de dados se um registro é duplicado. Para fazer isso, basta implementar a interface IHorseDTOValidator:
type
TValidadorCPF = class(TInterfacedObject, IHorseDTOValidator)
public
function Validate(const AValue: TValue; out AErrorMessage: string): Boolean;
end;
function TValidadorCPF.Validate(const AValue: TValue; out AErrorMessage: string): Boolean;
begin
Result := ValidarCPF(AValue.AsString); // Sua função interna de validação de CPF
if not Result then
AErrorMessage := 'CPF informado é inválido';
end;
Em seguida, basta aplicar o atributo na propriedade correspondente do DTO:
[CustomValidator(TValidadorCPF)]
property CPF: string read FCPF write FCPF;
Conclusão
Adotar o horse-dto é uma excelente decisão de arquitetura para quem busca construir APIs profissionais, limpas e escaláveis em Delphi. Ao desacoplar a lógica de validação de entrada de dados dos controllers, você ganha legibilidade, facilita a manutenção de testes e acelera a entrega de novos recursos.
Você já utiliza validação declarativa nas suas APIs Delphi? Deixe sua opinião nos comentários!

0 comentário(s)