Executando verificação de segurança...
2

[Dúvida] Como verificar se o corpo da requisição é válido?

Olá 👋, gostaria de uma pequena ajuda em relação a um projeto pessoal meu:

Estou desenvolvendo uma API utilizando TypeScript e Express. Durante o desenvolvimento de um endpoint, minha cabeça deu um "click" e uma dúvida quanto à validação do corpo da requisição grudou na minha testa e não saiu mais.

Para exemplificar veja o endpoint abaixo

router.put("/planets/:id", async (req: Request, res: Response) => {
    const repository: Repository<Planet> = database.getRepository(Planet);

    try {
        const id: number = parseInt(req.params.id);

        const planet: Planet = await repository.findOneBy({ id: id });
        if (!planet) {
            throw new ResourceNotFound("Planet com ID fornecido não foi encontrado.")
        }

        const { name, weather, terrain, population, stellarSystemId, ...rest } = req.body;
        if (Object.keys(rest).length > 0) {
            throw new InvalidRequestBody("Corpo da requisição inválido. planet deve conter somente 'name', 'weather', 'terrain', 'population' e 'stellarSystemId'.");
        }

        await repository.update({ id: id }, req.body);

        res.status(HTTPStatus.OK).send({
            "status": "success",
            "message": "Planet específicado alterado com sucesso.",
            "data": {
                "planet": await repository.findOneByOrFail({ id: id })
            }
        })
    } catch (error) {
        res.status(error.HTTPStatusCode || HTTPStatus.INTERNAL_SERVER_ERROR).send({
            "status": "error",
            "message": error.message || "Erro ao processar a requisição",
            "data": {}
        })
    }
})

Ignorando tudo que tem de errado, minha dúvida paira especificamente nesse trecho

const { name, weather, terrain, population, stellarSystemId, ...rest } = req.body;
if (Object.keys(rest).length > 0) {
    throw new InvalidRequestBody("Corpo da requisição inválido. planet deve conter somente 'name', 'weather', 'terrain', 'population' e 'stellarSystemId'.");
}

Nele eu capturo os valores do body da requisição e utilizo desestruturação para mapear cada uma das propriedades para dentro de variáveis. Se, ao fazer a requisição, o cliente enviar mais campos do que deveria, eles vão parar dentro da variável rest.

Problema

  1. Eu não sei se essa forma de fazer isso está "correta". Geralmente a resposta é depende, mas o que eu deveria levar em consideração aqui?
  2. No caso de ter muitas variáveis isso ficaria... feio. Existe uma forma menos verbosa ou "poluida" de fazer isso?

Agora em relação ao endpoint como um todo, você tem alguma sugestão, dica ou crítica?

Carregando publicação patrocinada...
4

Nessa caso é melhor usar Zod, é mais fácil de entender e você pode verificar se o que está sendo passado está correto.

import { z } from 'zod';

// Definindo o schema com Zod
const planetSchema = z.object({
  name: z.string(),
  weather: z.string(),
  terrain: z.string(),
  population: z.number(),
  stellarSystemId: z.string()
}).strict(); // O .strict() impede propriedades adicionais

// Uso no código
const result = planetSchema.safeParse(req.body);

if (!result.success) {
  throw new InvalidRequestBody(
    "Corpo da requisição inválido. planet deve conter somente 'name', 'weather', 'terrain', 'population' e 'stellarSystemId'."
  );
}

const { name, weather, terrain, population, stellarSystemId } = result.data;

Se você quiser validações mais específicas, pode adicionar regras como:

const planetSchema = z.object({
  name: z.string().min(1).max(100),
  weather: z.string().min(1),
  terrain: z.string().min(1),
  population: z.number().min(0),
  stellarSystemId: z.string().uuid()
}).strict();
2

Man, que bacana. Não conhecia o Zod ainda e estava me restringindo usar IA para pesquisar. Me parece que isso serve bem, então vou dar uma pesquisada e tentar implementar no projeto.🚀

2

como já responderam você pode usar libs para validação de schema como zod, joi, yup e etc, isso vai tornwr mais fácilde dar manutenção e de escalar caso vocêtenha que lidar com muitas propriedades.

sobre o seu exemplo, caso ele não cresça muito usar o destructuring já resolveria o problema de propriedades adicionais, visto que vc usa apenas as propriedades que seu backend vai de fato utilizar.