Node.js: Projeto API (Parte 1)

Última atualização: 2026-08-26

1. Lançamento do projeto: O primeiro dia da Alice

Alice e sua equipe receberam uma nova solicitação: desenvolver uma API de gerenciamento de tarefas em equipe. No primeiro dia, decidiram começar configurando a estrutura do projeto e o módulo de autenticação de usuários. “A autenticação é a base de tudo”, disse Alice. “Sem autenticação, o restante do sistema de gerenciamento de tarefas não teria sentido.”



2. Inicialização do projeto e estrutura de diretórios

▶ Exemplo:(1) Inicializar um projeto Express

BASH
mkdir task-manager-api && cd task-manager-api
npm init -y
npm install express mongoose bcryptjs jsonwebtoken dotenv cors helmet
npm install --save-dev nodemon

▶ Exemplo:(2) Projeto da estrutura de diretórios

TEXT 📖 Somente leitura
task-manager-api/
├── src/
│   ├── config/
│   │   └── db.js
│   ├── middleware/
│   │   └── auth.js
│   ├── models/
│   │   ├── User.js
│   │   └── Task.js
│   ├── routes/
│   │   ├── auth.js
│   │   └── tasks.js
│   ├── validators/
│   │   └── authValidator.js
│   └── app.js
├── .env
├── .gitignore
├── package.json
└── server.js
Diretório/Arquivo Descrição
src/config/ Conexão com o banco de dados, variáveis de ambiente e outras configurações
src/middleware/ Middleware para autenticação, tratamento de erros, etc.
src/models/ Definições de esquema e modelo do Mongoose
src/routes/ Módulos de roteamento, classificados por função
src/validators/ Lógica de validação de parâmetros de solicitação
src/app.js Arquivo principal do aplicativo Express
server.js Arquivo de entrada, iniciar o servidor

▶ Exemplo: arquivo de entrada server.js

JAVASCRIPT
require('dotenv').config();
const app = require('./src/app');
const connectDB = require('./src/config/db');

connectDB();

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});
▶ Experimente

▶ Exemplo: Configuração da conexão com o banco de dados

JAVASCRIPT
const mongoose = require('mongoose');

const connectDB = async () => {
  try {
    await mongoose.connect(process.env.MONGO_URI);
    console.log('MongoDB connected');
  } catch (err) {
    console.error('MongoDB connection error:', err.message);
    process.exit(1);
  }
};

module.exports = connectDB;
▶ Experimente

3. Projeto de modelos no Mongoose

(1) Modelo do usuário

Campo Tipo Obrigatório Descrição
username String Sim Nome de usuário, índice exclusivo
email String Sim E-mail, índice exclusivo
password String Sim senha com hash bcrypt
role String Não Função: user (padrão) / admin
createdAt Data Automático Data de criação

(2) Modelo de tarefa

Campo Tipo Obrigatório Descrição
title String Sim Título da tarefa
description String Não Detalhes da tarefa
status String Não pending (padrão) / in-progress / completed
priority String Não low (padrão) / medium / high
assignedTo ObjectId Sim Usuário designado, associado ao Usuário
dueDate Data Prazo
createdAt Data Automático Data de criação
updatedAt Data Automático Última atualização

▶ Exemplo: Definição do modelo de usuário

JAVASCRIPT
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

const userSchema = new mongoose.Schema({
  username: { type: String, required: true, unique: true, trim: true },
  email: { type: String, required: true, unique: true, lowercase: true },
  password: { type: String, required: true, minlength: 6 },
  role: { type: String, enum: ['user', 'admin'], default: 'user' }
}, { timestamps: true });

userSchema.pre('save', async function (next) {
  if (!this.isModified('password')) return next();
  this.password = await bcrypt.hash(this.password, 10);
  next();
});

userSchema.methods.comparePassword = function (candidate) {
  return bcrypt.compare(candidate, this.password);
};

module.exports = mongoose.model('User', userSchema);
▶ Experimente

▶ Exemplo: Definição do modelo de tarefa

JAVASCRIPT
const mongoose = require('mongoose');

const taskSchema = new mongoose.Schema({
  title: { type: String, required: true, trim: true },
  description: { type: String, default: '' },
  status: { type: String, enum: ['pending', 'in-progress', 'completed'], default: 'pending' },
  priority: { type: String, enum: ['low', 'medium', 'high'], default: 'low' },
  assignedTo: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
  dueDate: { type: Date }
}, { timestamps: true });

module.exports = mongoose.model('Task', taskSchema);
▶ Experimente

4. Módulo de autenticação do usuário

▶ Exemplo:(1) Como funciona a autenticação JWT

100%
graph TD
    A[User Registration/Log In] --> B[Server Authentication Credentials]
    B --> C[Generate JWT Token]
    C --> D[Back Token To the client]
    D --> E[Client-side Token Request]
    E --> F[auth Middleware Validation Token]
    F -->|Valid| G[Forward to the routing processor]
    F -->|Invalid| H[Back 401 Error]

(2) Projeto dos pontos de extremidade da API de autenticação

Método Caminho Descrição Autenticação necessária
POST /api/auth/register Cadastro de usuário Não
POST /api/auth/login Login do usuário Não
GET /api/auth/me Obter usuário atual Sim

▶ Exemplo: Rotas de cadastro e login

JAVASCRIPT
const router = require('express').Router();
const jwt = require('jsonwebtoken');
const User = require('../models/User');

const generateToken = (id) => jwt.sign({ id }, process.env.JWT_SECRET, { expiresIn: '7d' });

router.post('/register', async (req, res, next) => {
  try {
    const { username, email, password } = req.body;
    const user = await User.create({ username, email, password });
    res.status(201).json({ token: generateToken(user._id), user: { id: user._id, username, email, role: user.role } });
  } catch (err) {
    next(err);
  }
});

router.post('/login', async (req, res, next) => {
  try {
    const { email, password } = req.body;
    const user = await User.findOne({ email });
    if (!user || !(await user.comparePassword(password))) {
      return res.status(401).json({ message: 'Invalid credentials' });
    }
    res.json({ token: generateToken(user._id), user: { id: user._id, username: user.username, email, role: user.role } });
  } catch (err) {
    next(err);
  }
});

module.exports = router;
▶ Experimente

▶ Exemplo: middleware de autenticação

JAVASCRIPT
const jwt = require('jsonwebtoken');
const User = require('../models/User');

module.exports = async (req, res, next) => {
  const header = req.headers.authorization;
  if (!header || !header.startsWith('Bearer ')) {
    return res.status(401).json({ message: 'No token provided' });
  }
  try {
    const decoded = jwt.verify(header.split(' ')[1], process.env.JWT_SECRET);
    req.user = await User.findById(decoded.id).select('-password');
    if (!req.user) return res.status(401).json({ message: 'User not found' });
    next();
  } catch {
    res.status(401).json({ message: 'Invalid token' });
  }
};
▶ Experimente

▶ Exemplo: Obter a rota do usuário atual

JAVASCRIPT
const auth = require('../middleware/auth');

router.get('/me', auth, async (req, res) => {
  res.json({ user: { id: req.user._id, username: req.user.username, email: req.user.email, role: req.user.role } });
});
▶ Experimente

5. O arquivo principal app.js e a configuração do arquivo .env

▶ Exemplo: Integrando o app.js

JAVASCRIPT
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const authRoutes = require('./routes/auth');

const app = express();

app.use(helmet());
app.use(cors());
app.use(express.json());

app.use('/api/auth', authRoutes);

app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(err.statusCode || 500).json({ message: err.message || 'Server Error' });
});

module.exports = app;
▶ Experimente

▶ Exemplo: Variáveis de ambiente no arquivo .env

TEXT 📖 Somente leitura
PORT=3000
MONGO_URI=mongodb://localhost:27017/task-manager
JWT_SECRET=your_super_secret_key_change_in_production


6. Exemplo abrangente: o processo completo de inicialização do projeto

O código a seguir integra todos os módulos principais mencionados acima. Com cerca de 80 linhas de código principal, é possível executar uma API básica de gerenciamento de tarefas com autenticação:

JAVASCRIPT
// server.js
require('dotenv').config();
const express = require('express');
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const cors = require('cors');
const helmet = require('helmet');

const app = express();
app.use(helmet(), cors(), express.json());

// --- Models ---
const userSchema = new mongoose.Schema({
  username: { type: String, required: true, unique: true },
  email: { type: String, required: true, unique: true },
  password: { type: String, required: true },
  role: { type: String, enum: ['user', 'admin'], default: 'user' }
}, { timestamps: true });
userSchema.pre('save', async function () { if (this.isModified('password')) this.password = await bcrypt.hash(this.password, 10); });
userSchema.methods.comparePassword = function (pw) { return bcrypt.compare(pw, this.password); };
const User = mongoose.model('User', userSchema);

// --- Auth Middleware ---
const auth = async (req, res, next) => {
  try {
    const decoded = jwt.verify(req.headers.authorization?.split(' ')[1], process.env.JWT_SECRET);
    req.user = await User.findById(decoded.id).select('-password');
    next();
  } catch { res.status(401).json({ message: 'Unauthorized' }); }
};

// --- Routes ---
app.post('/api/auth/register', async (req, res) => {
  const user = await User.create(req.body);
  const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '7d' });
  res.status(201).json({ token, user: { id: user._id, username: user.username, role: user.role } });
});
app.post('/api/auth/login', async (req, res) => {
  const user = await User.findOne({ email: req.body.email });
  if (!user || !(await user.comparePassword(req.body.password))) return res.status(401).json({ message: 'Invalid credentials' });
  const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '7d' });
  res.json({ token, user: { id: user._id, username: user.username, role: user.role } });
});
app.get('/api/auth/me', auth, (req, res) => res.json(req.user));

// --- Start ---
mongoose.connect(process.env.MONGO_URI).then(() => {
  app.listen(process.env.PORT || 3000, () => console.log('Server running'));
});

❓ Perguntas Frequentes

P: Como a estrutura de diretórios do projeto deve ser projetada? R: Organize-a por funcionalidade: armazene os modelos de dados em models/, as rotas em routes/, o middleware em middleware/ e as configurações em config/. Coloque o ponto de entrada, app.js, no diretório raiz.

P: Por que usar o Mongoose em vez do driver nativo? R: O Mongoose oferece validação de esquema, ganchos de middleware, dicas de tipo e um construtor de consultas, o que aumenta a eficiência do desenvolvimento; o driver nativo é mais leve e mais adequado para cenários simples.

P: O arquivo .env deve ser incluído no Git? R: De jeito nenhum. O arquivo .env contém informações confidenciais, como senhas de banco de dados e chaves; portanto, deve ser adicionado ao .gitignore e inserido por meio de variáveis de ambiente ou de CI durante a implantação.

P: Qual deve ser o comprimento do segredo JWT? R: Deve ser uma sequência aleatória de pelo menos 32 caracteres; para ambientes de produção, recomenda-se 64 caracteres ou mais. Você pode gerar um usando node -e "console.log(require('crypto').randomBytes(64).toString('hex'))".

P: Como faço para testar a API de registro? R: Use o Postman ou o curl para enviar uma solicitação POST para /api/auth/register, verifique o token retornado e, em seguida, use esse token para acessar uma rota protegida e verificar se a autenticação está funcionando.


📖 Resumo

📝 Exercícios

  1. Inicialize o projeto de acordo com a estrutura de diretórios, instale todas as dependências e certifique-se de que npm run dev consiga iniciar o servidor.
  2. Crie dois modelos Mongoose, User e Task, e use o Postman para testar as APIs de cadastro e login.
  3. Escreva um middleware de autenticação e teste o endpoint /api/auth/me: ele deve retornar um erro 401 se nenhum token for fornecido e retornar as informações do usuário se um token válido for fornecido.
  4. Configure JWT_SECRET e MONGO_URI no arquivo .env e ignore o arquivo .env no diretório .gitignore.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%