Criando Validações de Endpoints com Zod
Tags: javascript, typescript, zod, node
Published: 2024-01-12 23:21:34

## Introdução

A validação de parâmetros de entrada é um aspecto crucial no desenvolvimento de APIs robustas e seguras. Utilizando o Express em conjunto com a biblioteca Zod, podemos criar esquemas de validação eficientes e precisos. Neste artigo, vamos demonstrar como criar validações de parâmetros de endpoints, exemplificando a criação de esquemas e sua aplicação nas rotas do Express.

## Definindo os Esquemas com Zod

### Arquivo `product.schema.ts`

Primeiro, definimos os esquemas de validação para as operações de criação e atualização de produtos.

```typescript
// product.schema.ts
import { z } from 'zod';
import { customIdSchema, dateSchema } from './common.schema';

export const createProductSchema = z.object({
  productId: customIdSchema('ID do produto é obrigatório'),
  name: z.string().min(1, 'Nome do produto é obrigatório'),
  price: z.number().min(0, 'Preço do produto deve ser positivo'),
  expirationDate: dateSchema({
    required_error: 'Data de validade é obrigatória',
  }),
});

export const updateProductSchema = createProductSchema.partial();
```

### Arquivo `product.model.ts`

Definimos os tipos de dados inferidos a partir dos esquemas.

```typescript
// product.model.ts
import { z } from 'zod';
import {
  createProductSchema,
  updateProductSchema,
} from './schemas/product.schema';

export type CreateProductRepository = z.infer<typeof createProductSchema>;
export type UpdateProductRepository = z.infer<typeof updateProductSchema>;
```

## Definindo as Rotas com Express

### Arquivo `product.route.ts`

Neste arquivo, definimos as rotas do Express e aplicamos as validações.

```typescript
// product.route.ts
import express from 'express';
import { productController } from '@controllers/product.controller';
import { validateCreateProduct, validateUpdateProduct } from '@validations/product.validation';

const router = express.Router();

router.post(
  '/products',
  validateCreateProduct,
  productController.createProduct,
);

router.get(
  '/products/:id',
  productController.getProduct,
);

router.put(
  '/products/:id',
  validateUpdateProduct,
  productController.updateProduct,
);

export default router;
```

## Implementando as Funções de Validação

### Arquivo `product.validation.ts`

Implementamos as funções de validação para serem usadas nas rotas.

```typescript
// product.validation.ts
import { Request, Response, NextFunction } from 'express';
import { createProductSchema, updateProductSchema } from '@models/schemas/product.schema';

export const validateCreateProduct = (
  req: Request,
  res: Response,
  next: NextFunction,
) => {
  const validationObj = createProductSchema.safeParse(req.body);

  if (!validationObj.success) {
    return res.status(400).send({ errors: validationObj.error.issues });
  }

  next();
};

export const validateUpdateProduct = (
  req: Request,
  res: Response,
  next: NextFunction,
) => {
  const validationObj = updateProductSchema.safeParse(req.body);

  if (!validationObj.success) {
    return res.status(400).send({ errors: validationObj.error.issues });
  }

  next();
};
```

Certamente, vamos expandir o artigo com exemplos de como os erros são retornados nos endpoints quando as validações falham.

## Exibindo os Erros de Validação nos Endpoints

Após a implementação das funções de validação utilizando Zod, quando uma solicitação não atende aos critérios definidos no esquema, a API retorna uma resposta contendo detalhes dos erros. Esses detalhes são derivados do objeto `issues` presente no objeto de erro gerado pelo Zod. Vamos ver como isso se traduz em respostas de API.

### Exemplo de Resposta de Erro

Considerando o endpoint para a criação de um produto (`POST /products`), se o cliente enviar uma solicitação com dados inválidos, a API responderá com uma mensagem de erro estruturada.

#### Solicitação com Dados Inválidos

```json
POST /products
{
  "name": "",
  "price": -10
}
```

#### Resposta da API

```json
HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "errors": [
    {
      "path": ["name"],
      "message": "Nome do produto é obrigatório"
    },
    {
      "path": ["price"],
      "message": "Preço do produto deve ser positivo"
    }
  ]
}
```

Neste exemplo, a API retorna um status HTTP 400 (Bad Request) com um corpo de resposta contendo um array de erros. Cada erro inclui o `path`, que identifica o campo com problema, e a `message`, que fornece uma descrição legível do erro.

### Vantagens desta Abordagem

- **Clareza**: Os erros são retornados de forma estruturada, facilitando a identificação de qual campo falhou na validação.
- **Flexibilidade**: O Zod permite customizar as mensagens de erro, tornando-as mais úteis para os desenvolvedores e usuários finais.
- **Consistência**: O uso de uma biblioteca de validação como Zod garante que os erros sejam tratados de maneira consistente em toda a aplicação.

## Conclusão

Integrar Zod com Express para a validação de parâmetros de endpoints oferece uma abordagem robusta e flexível para garantir a integridade dos dados de entrada em uma API. Com respostas de erro estruturadas e informativas, os desenvolvedores e usuários finais podem facilmente entender e corrigir erros nos dados enviados, melhorando a usabilidade e confiabilidade da aplicação. Esta integração destaca-se como uma prática eficiente no desenvolvimento de APIs modernas e seguras.