Curso de Node.js e Backend

Jul 22, 2024

Curso de Node.js e Backend

Introdução

  • Primeira aula do evento de programação backend.
  • Criação de uma API utilizando Node.js e outras tecnologias.
  • Importância de deixar feedback nos comentários.
  • Compartilhar o evento com outros interessados.

Tecnologias Utilizadas

  • Node.js: Usado como servidor backend e tradutor de JavaScript para a linguagem de máquina.
  • Prisma: ORM (Object-Relational Mapping) utilizado para interagir com o banco de dados. Recomenda-se o uso com TypeScript, mas usamos JavaScript nesta aula.
  • Docker e Docker Compose: Utilizados para criar e gerenciar contêineres com banco de dados PostgreSQL localmente.
  • Sucrase: Utilizado para transpilar o código de ES6+ para versões mais antigas do JavaScript, melhorando a compatibilidade e performance.
  • Yup: Biblioteca para validação de esquemas de dados.

Preparação do Ambiente

Instalação do Node.js

  • Acessar o site oficial nodejs.org e baixar a versão LTS.
  • Verificar a instalação com o comando node -v e npm -v.
  • Instalação do yarn com npm install -g yarn.

Configuração do Docker

  1. Criar contêiner PostgreSQL usando Docker Compose:
    version: '3'
    services:
      db_postgres_evento:
        image: postgres:alpine
        ports:
        - '5435:5432'
        environment:
          POSTGRES_USER: 'pguser'
          POSTGRES_PASSWORD: 'pgpassword'
          POSTGRES_DB: 'mydb'
        volumes:
        - './db_data:/var/lib/postgresql/data'
    
  2. Comando para iniciar o Docker Compose:
    docker-compose up -d
    
    • -d para rodar em segundo plano.
    • Verificar com docker ps.

Configuração do Projeto

Estrutura Principal

  1. Inicializar projeto Node.js com Yarn:
    yarn init -y
    
  2. Instalar dependências:
    yarn add express cors dotenv prisma @prisma/client nodemon sucrase bcrypt yup
    

Configuração do Prisma

  1. Inicialização e configuração básica do Prisma:
    yarn prisma init
    
  2. Configuração do banco de dados em .env:
    DATABASE_URL='postgresql://pguser:pgpassword@localhost:5435/mydb'
    
  3. Definição do esquema Prisma em prisma/schema.prisma:
    model User {
      id        Int      @id @default(autoincrement())
      name      String
      email     String   @unique
      password  String
      phone     String?
      createdAt DateTime @default(now())
      updatedAt DateTime @updatedAt
    }
    
  4. Executar migrações para aplicar esquema:
    yarn prisma migrate dev --name init
    

Desenvolvimento da API

Estrutura de Pasta

  • src/: Contém todo o código fonte.
  • src/services/: Configuração do Prisma Client.
  • src/repositories/: Conexão direta com banco de dados utilizando Prisma.
  • src/controllers/: Contém a lógica de controle da API.
  • src/routes/: Definição das rotas da API.
  • src/validations/: Validações utilizando Yup.

Configurações Iniciais do Index.js

  1. Instanciar servidor e middlewares:
    import express from 'express';
    import cors from 'cors';
    import dotenv from 'dotenv';
    
    dotenv.config();
    
    const app = express();
    app.use(cors());
    app.use(express.json());
    
    app.use(require('./routes'));
    
    app.listen(3001, () => console.log('Servidor iniciou'));
    
  2. Configuração do Nodemon e Sucrase em package.json:
    "scripts": {
       "start": "nodemon src/index.js --exec 'node -r sucrase/register'"
    }
    

CRUD de Usuários com Prisma

  1. Criação de Usuário
    // src/repositories/user.repository.js
    import { prisma } from '../services/prisma';
    
    export const createUser = async (data) => {
       const user = await prisma.user.create({ data });
       return user;
    };
    
    // src/controllers/user.controller.js
    import { createUser } from '../repositories/user.repository';
    import bcrypt from 'bcrypt';
    
    export const create = async (req, res) => {
       const hashPassword = await bcrypt.hash(req.body.password, 10);
       req.body.password = hashPassword;
       const user = await createUser(req.body);
       res.status(201).json(user);
    };
    
    // src/routes/index.js
    import { Router } from 'express';
    import { create } from '../controllers/user.controller';
    
    const routes = Router();
    routes.post('/users', create);
    
    export default routes;
    
  2. Leitura de Usuários
    // src/repositories/user.repository.js
    export const getAllUsers = async () => {
       return await prisma.user.findMany();
    };
    
    // src/controllers/user.controller.js
    import { getAllUsers } from '../repositories/user.repository';
    
    export const findAll = async (req, res) => {
       const users = await getAllUsers();
       res.json(users);
    };
    
    // src/routes/index.js
    routes.get('/users', findAll);
    
  3. Leitura de Usuário por ID
    // src/repositories/user.repository.js
    export const getUserById = async (id) => {
       return await prisma.user.findUnique({ where: { id: Number(id) } });
    };
    
    // src/controllers/user.controller.js
    import { getUserById } from '../repositories/user.repository';
    
    export const findById = async (req, res) => {
       const user = await getUserById(req.params.id);
       res.json(user);
    };
    
    // src/routes/index.js
    routes.get('/users/:id', findById);
    
  4. Atualização de Usuário
    // src/repositories/user.repository.js
    export const updateUser = async (id, data) => {
       return await prisma.user.update({ where: { id: Number(id) }, data });
    };
    
    // src/controllers/user.controller.js
    import { updateUser } from '../repositories/user.repository';
    
    export const update = async (req, res) => {
       const user = await updateUser(req.params.id, req.body);
       res.json(user);
    };
    
    // src/routes/index.js
    routes.put('/users/:id', update);
    
  5. Exclusão de Usuário
    // src/repositories/user.repository.js
    export const deleteUser = async (id) => {
       return await prisma.user.delete({ where: { id: Number(id) } });
    };
    
    // src/controllers/user.controller.js
    import { deleteUser } from '../repositories/user.repository';
    
    export const remove = async (req, res) => {
       await deleteUser(req.params.id);
       res.status(204).send();
    };
    
    // src/routes/index.js
    routes.delete('/users/:id', remove);
    

Validação de Dados com Yup

  • Definir as validações em user.Validations.js:
    import * as yup from 'yup';
    
    export const userSchema = yup.object().shape({
       name: yup.string().required(),
       email: yup.string().email().required(),
       password: yup.string().min(6).required(),
       phone: yup.string().nullable(),
    });
    
  • Implementar as validações no Controller:
    import { userSchema } from '../validations/user.validations';
    
    export const create = async (req, res) => {
       try {
          await userSchema.validate(req.body, { abortEarly: false });
       } catch (error) {
          return res.status(400).json(error.errors);
       }
    
       const hashPassword = await bcrypt.hash(req.body.password, 10);
       req.body.password = hashPassword;
    
       const user = await createUser(req.body);
       res.status(201).json(user);
    };
    
  • Validações aplicáveis para inserção (POST) e atualização (PUT).

Encerramento

  • API funcional com CRUD completo para gerenciamento de usuários.
  • Revisar o código fonte e documentação (boas práticas).
  • Previsão de futuras aulas para adaptação do backend para produção com técnicas avançadas.
  • Encaminhar feedback e compartilhar o evento com interessados.

Próximos Passos:

  • Preparar ambiente de produção (build, deployment).
  • Continuação do frontend.