Dev Doido.

Endpoint de SignUp nas Routes do Fastify no CrazyStack Node.js

Gustavo Miranda
Gustavo Miranda
- ... visualizações

Bem vindos à aula sobre o endpoint de SignUp nas rotas do Fastify. Neste módulo, aprenderemos como criar o endpoint de registro de usuários em nossa API. Discutiremos como configurar as rotas no Fastify e como ligá-las ao controlador de registro de usuários. Além disso, mostraremos como lidar com erros e fornecer uma resposta apropriada para o cliente. Ao final desta aula, você terá uma compreensão clara de como implementar o endpoint de registro de usuários em sua API com Fastify.

Este artigo servirá como uma espécie de documentação de alguns códigos vistos durante as aulas apenas como material complementar.

import { requestContext } from "@fastify/request-context";
import { HttpRequest } from "@/application/helpers";
import { Controller } from "@/application/infra/contracts";

export const adaptRoute = (controller: Controller) => {
  return async (request: any, reply: any) => {
    const { body, params, query, headers } = request;
    const { userId = null, userLogged = null } = requestContext.get("context") || {};
    const httpRequest: HttpRequest = {
      body,
      params,
      headers,
      userId,
      query,
      userLogged,
    };
    const { statusCode, data } = await controller.handle(httpRequest);
    reply.code(statusCode).send(data);
  };
};

Essa é uma função que adapta um controller da aplicação para ser utilizado como uma rota do Fastify. A função recebe um objeto do tipo Controller e retorna uma nova função, que será usada como endpoint na rota. Essa função de endpoint recebe como parâmetros o request e o reply, que são padrões do Fastify.

A função de endpoint extrai informações importantes do request, como o corpo (body), parâmetros (params), query, headers, informações do usuário logado e o seu ID, e as armazena em um objeto HttpRequest. Essas informações serão passadas para o método handle do controller, que deverá tratar essa requisição e retornar um objeto com o statusCode e os dados para a resposta.

Por fim, a função de endpoint seta o statusCode retornado pelo controller como o código HTTP da resposta e envia os dados como corpo da resposta. Caso estivéssemos usando Express no projeto a adaptação da rota seria da seguinte forma:

import { Request, Response } from "express";
import { Controller } from "@/application/infra/contracts";

export const adaptRoute = (controller: Controller) => {
  return async (req: Request, res: Response) => {
    const httpRequest = {
      body: req.body,
      params: req.params,
      headers: req.headers,
      query: req.query,
      userId: req.userId,
      userLogged: req.user,
    };
    const { statusCode, data } = await controller.handle(httpRequest);
    res.status(statusCode).send(data);
  };
};

Neste exemplo, a função adaptRoute recebe um objeto do tipo Controller e retorna uma função que recebe dois parâmetros req e res. Estes parâmetros representam, respectivamente, a requisição feita pelo usuário e a resposta que será enviada para ele.

A função adaptRoute é responsável por transformar as informações da requisição em um objeto HttpRequest e passá-lo para o método handle do objeto controller. Em seguida, ela captura a resposta retornada pelo controller e a envia de volta para o usuário, configurando o código de status da resposta com o valor de statusCode e os dados com o valor de data.

import { adaptRoute } from "@/application/adapters";
import { makeSignupController } from "@/slices/user/controllers";

export const signupAdapter = () => adaptRoute(makeSignupController());

O código acima é uma implementação de um adapter para a rota de signup no Fastify. A função adaptRoute é importada do módulo de adapters e é usada para adaptar o controlador makeSignupController a uma função que possa ser usada em uma rota do Fastify. A função makeSignupController retorna um controlador de signup configurado e pronto para ser usado. O adapter é responsável por encapsular a lógica do controlador e adaptá-lo a uma função que possa ser usada como rota pelo Fastify.

const bodyJsonSchema = {
  type: "object",
  required: ["email", "password", "passwordConfirmation", "name", "role", "coord"],
  properties: {
    name: { type: "string" },
    email: { type: "string" },
    password: { type: "string" },
    passwordConfirmation: { type: "string" },
    coord: {
      type: "object",
      properties: {
        type: { type: "string", enum: ["Point"] },
        coordinates: { type: "array", items: { type: "number" } },
      },
    },
    role: { type: "string", enum: ["client", "owner", "visitor"] },
  },
};
const signupResponse = {
  200: {
    type: "object",
    properties: {
      refreshToken: { type: "string" },
      accessToken: { type: "string" },
      user: {
        type: "object",
        properties: {
          _id: { type: "string" },
          email: { type: "string" },
          name: { type: "string" },
          role: { type: "string" },
          active: { type: "boolean" },
          coord: {
            type: "object",
            properties: {
              type: { type: "string", enum: ["Point"] },
              coordinates: { type: "array", items: { type: "number" } },
            },
          },
        },
      },
    },
  },
};
export const signupPostSchema = {
  schema: {
    body: bodyJsonSchema,
    response: signupResponse,
  },
};

Essa é uma definição de JSON Schema para a rota de signup em uma API. Ele define o corpo da requisição e a resposta esperada.

A propriedade "body" especifica os campos obrigatórios que devem estar presentes na requisição POST: "email", "password", "passwordConfirmation", "name", "role" e "coord". Cada um desses campos tem seu próprio tipo de dado especificado (por exemplo, "email" é do tipo "string").

A propriedade "response" especifica a resposta esperada da API, caso a requisição seja bem-sucedida (statusCode 200). A resposta inclui um refreshToken, um accessToken, e um objeto de usuário, cada um com seus próprios campos.

Este JSON Schema é usado para validar a entrada e a saída da API e garantir que a API esteja funcionando corretamente.

import { signupAdapter } from "./authAdapter";
import { signupPostSchema } from "./authSchema";

async function auth(fastify: any, options: any) {
  fastify.post("/auth/signup", signupPostSchema, signupAdapter());
}
export { auth };

Este é o arquivo de rotas de autenticação no Fastify. Aqui, estamos importando a função signupAdapter do arquivo authAdapter e o esquema de validação de solicitação signupPostSchema do arquivo authSchema.

Em seguida, estamos criando a função auth que registra uma rota POST para o endpoint /auth/signup e passa o signupPostSchema como o esquema de validação de solicitação. Além disso, a função signupAdapter é passada como o tratador da rota para manipular as solicitações deste endpoint. Se estivéssemos usando Express, para implementar a mesma coisa ficaria da seguinte forma:

import express from "express";
import { signupAdapter } from "./signupAdapter";

const app = express();

app.post("/signup", signupAdapter());

Neste exemplo, uma nova rota é criada usando o método post do Express, com o endpoint /signup. A função retornada pelo adapter signupAdapter é passada como segundo argumento para a rota. Quando uma requisição POST é feita para o endpoint /signup, a função adaptada será executada e fará o trabalho de lidar com a requisição, validar os dados, e retornar uma resposta adequada.

LINK DO COMMIT

LINK DO REPOSITÓRIO