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

Dev Doido - Feb 27 '23 - - Dev Community

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 é um material auxiliar do bootcamp CrazyStack Node.js do DevDoido. Ele servirá como uma espécie de documentação de alguns códigos vistos durante as aulas apenas como material complementar, garanta já sua vaga no bootcamp clicando AQUI!.

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);
  };
};
Enter fullscreen mode Exit fullscreen mode

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);
  };
};
Enter fullscreen mode Exit fullscreen mode

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());
Enter fullscreen mode Exit fullscreen mode

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,
  },
};
Enter fullscreen mode Exit fullscreen mode

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 };
Enter fullscreen mode Exit fullscreen mode

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());
Enter fullscreen mode Exit fullscreen mode

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

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .