Criando Value-Objects e Entidades com Zod

Introdução

No design de software orientado a domínio (Domain-Driven Design, ou DDD), o conceito de Value-Objects e Entidades é fundamental para criar um modelo de domínio expressivo e consistente. Value-Objects representam elementos do domínio que não possuem identidade própria, sendo definidos por seu conjunto de atributos. Já as Entidades possuem uma identidade única que as diferencia de outras instâncias, mesmo que seus atributos sejam iguais.

Value-Objects

Value-Objects são imutáveis e comparados por valor. Eles encapsulam conceitos que são inerentemente sem identidade, como uma data ou um endereço. Por serem imutáveis, os Value-Objects garantem consistência e ajudam a evitar estados inválidos no sistema.

Entidades

As Entidades, por outro lado, são objetos que possuem uma identidade única e são comparadas por essa identidade, não pelos valores dos seus atributos. Uma Entidade mantém um ciclo de vida, enquanto um Value-Object pode ser substituído sem afetar a integridade do sistema.

O que é o Zod?

Zod é uma biblioteca TypeScript para validação e definição de esquemas. Ela permite criar e validar esquemas de dados de maneira simples e eficaz. Zod é especialmente útil quando se deseja garantir que os objetos no domínio do sistema estejam sempre em um estado válido.

Usando Zod para Criar Value-Objects e Entidades

Definindo um Value-Object com Zod

Vamos começar criando um Value-Object para representar um endereço. Usaremos o Zod para garantir que o endereço seja sempre válido.

import { z } from "zod";

const EnderecoSchema = z.object({
  rua: z.string().min(1, "Rua não pode ser vazia"),
  cidade: z.string().min(1, "Cidade não pode ser vazia"),
  estado: z.string().min(2, "Estado deve ter pelo menos 2 caracteres"),
  cep: z.string().regex(/^\d{5}-\d{3}$/, "CEP inválido"),
});

class Endereco {
  constructor(public readonly props: z.infer<typeof EnderecoSchema>) {}

  static criar(props: z.infer<typeof EnderecoSchema>): Endereco {
    EnderecoSchema.parse(props); // Validação do esquema
    return new Endereco(props);
  }
}

// Uso
const endereco = Endereco.criar({
  rua: "Rua A",
  cidade: "Cidade B",
  estado: "CE",
  cep: "12345-678",
});

Definindo uma Entidade com Zod

Para definir uma Entidade, precisaremos de um identificador único. Vamos criar uma Entidade Cliente que possui um identificador e outros atributos validados por Zod.

import { v4 as uuidv4 } from "uuid";

const ClienteSchema = z.object({
  nome: z.string().min(1, "Nome não pode ser vazio"),
  email: z.string().email("Email inválido"),
  idade: z.number().min(18, "Idade mínima é 18 anos"),
});

class Cliente {
  public readonly id: string;
  constructor(public readonly props: z.infer<typeof ClienteSchema>) {
    this.id = uuidv4();
  }

  static criar(props: z.infer<typeof ClienteSchema>): Cliente {
    ClienteSchema.parse(props); // Validação do esquema
    return new Cliente(props);
  }
}

// Uso
const cliente = Cliente.criar({
  nome: "João Silva",
  email: "joao@example.com",
  idade: 30,
});

Conclusão

A utilização do Zod para definir e validar Value-Objects e Entidades em um contexto de DDD não só garante a integridade dos dados, mas também ajuda a manter um modelo de domínio claro e consistente. Value-Objects e Entidades bem definidos promovem um design de software mais robusto e fácil de manter. Experimente aplicar essas técnicas no seu próximo projeto e veja como elas podem transformar a forma como você lida com a validação de dados.

Comentários

Postagens mais visitadas deste blog

Um caso de uso não deve depender de outro caso de uso

O que são Aggregates?

Repositórios não devem ser disponibilizado para os clientes