Arquitetura da API de Produção 🏗️
Para garantir a manutenção do sistema, implementei um padrão de Model-View-Controller (MVC) rigoroso.
Modelos
Os modelos foram definidos com Mongoose para lidar com esquemas complexos, incluindo uma referência de autor que liga Blogs a Usuários.
const mongoose = require('mongoose');
const blogSchema = new mongoose.Schema({
title: String,
body: String,
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
});
Controladores
Os controladores são a “mente” da engrenagem, gerenciando o fluxo de dados e lidando com interações assíncronas com o MongoDB.
const express = require('express');
const router = express.Router();
const Blog = require('./models/Blog');
router.get('/blogs', async (req, res) => {
const blogs = await Blog.find().exec();
res.json(blogs);
});
Lógica de Estado
Os artigos passam por estados diferentes, incluindo rascunho e publicado. Implementei guardas de segurança para garantir que rascunhos permaneçam privados enquanto conteúdo publicado é exibido na feed pública.
const mongoose = require('mongoose');
const blogSchema = new mongoose.Schema({
title: String,
body: String,
state: {
type: String,
enum: ['draft', 'published']
}
});
blogSchema.pre('save', async function(next) {
if (this.state === 'draft') {
this.private = true;
} else {
this.private = false;
}
next();
});
A arquitetura MVC contribui para a manutenção do sistema ao separar responsabilidades e permitir a fácil modificação ou substituição de qualquer componente sem afetar o resto do sistema.
Implementação de Recursos Avançados 🤖
Automatização do Algoritmo de Tempo de Leitura
Para automatizar o cálculo do tempo de leitura, utilizei Mongoose hooks para analisar o conteúdo do texto antes da salvação do documento. O código abaixo demonstra como isso foi feito:
// Define o esquema do blog
const blogSchema = new mongoose.Schema({
// ...
body: String,
reading_time: Number
});
// Utilize o hook 'pre-save' para calcular o tempo de leitura
blogSchema.pre('save', async function() {
if (this.body) {
const wordsPerMinute = 200;
const words = this.body.split(/\s+/).length;
this.reading_time = Math.ceil(words / wordsPerMinute);
}
});
Segurança com JWT
Para implementar a segurança com JWT, utilizei o middleware para verificar a validade do token em cada rota protegida. O código abaixo demonstra como isso foi feito:
// Defina o middleware para verificar o token JWT
const jwtMiddleware = async (req, res, next) => {
const token = req.header('Authorization');
if (!token) return res.status(401).send({ error: 'Token não fornecido' });
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (error) {
res.status(400).send({ error: 'Token inválido' });
}
};
// Utilize o middleware em cada rota protegida
router.get('/protected', jwtMiddleware, async (req, res) => {
// ...
});
Esses recursos melhoram a funcionalidade e a segurança da API, permitindo que os usuários acessem conteúdo protegido e que o tempo de leitura seja calculado automaticamente.
Depuração e Solução de Problemas
O Conflito de Porta AirPlay (Port 5000)
Encontrei um problema persistente de 404 onde meu servidor parecia estar rodando, mas o Postman não conseguia encontrar minhas rotas.
// macOS Monterey usa a porta 5000 para o AirPlay Receiver
// Migrar o ambiente local para a porta 3000 resolveu o conflito instantaneamente
Erros de Chave Duplicada (E11000)
Enquanto escrevia testes automatizados com Jest, eu atingi erros E11000 de chaves duplicadas.
// Implementar "Ativos de Dados Únicos" para o conjunto de testes, usando timestamps (Date.now()) para e-mails de usuário para garantir que cada execução de teste tenha um banco de dados isolado
Importância da Depuração e Testes
A depuração e testes são fundamentais para garantir a robustez e a escalabilidade de uma API. É crucial identificar e resolver problemas como o conflito de porta e erros de chave duplicada para garantir que a API seja estável e confiável.
Garantia de Qualidade e Testes
Abordagem de Garantia de Qualidade
Para garantir a robustez e a confiabilidade da API, foi implementada uma abordagem de garantia de qualidade que inclui a criação de uma suíte de testes abrangente com Jest e Supertest.
Suíte de Testes com Jest e Supertest
A suíte de testes foi criada utilizando Jest e Supertest, que permitem testar a API de forma eficaz e eficiente. A suíte de testes inclui 22 testes que cobrem diferentes cenários, incluindo:
* Autenticação (Signup, Login, Logout)
* Busca e precisão de regex
* Controle de autorização (garantindo que o usuário B não possa deletar o trabalho do usuário A)
* Incremento de leitura de métricas
Código de Exemplo
import request from 'supertest';
import app from '../app';
describe('Autenticação', () => {
it('Deve realizar o login com sucesso', async () => {
const response = await request(app).post('/login').send({ email: 'user@example.com', password: 'password' });
expect(response.status).toBe(200);
});
it('Deve realizar o logout com sucesso', async () => {
const response = await request(app).post('/logout');
expect(response.status).toBe(200);
});
});
Garantia de Qualidade
A abordagem de garantia de qualidade implementada garante que a API seja robusta e confiável, pois:
* A suíte de testes abrangente cobre diferentes cenários e garantindo que a API funcione corretamente
* A utilização de Jest e Supertest permite testar a API de forma eficaz e eficiente
* A criação de uma suíte de testes permite identificar e corrigir problemas de forma rápida e eficaz
Conclusão
A abordagem de garantia de qualidade implementada garante que a API seja robusta e confiável, permitindo que os usuários tenham uma experiência de utilização satisfatória. A suíte de testes abrangente e a utilização de Jest e Supertest permitem identificar e corrigir problemas de forma rápida e eficaz, garantindo a qualidade da API.
Implantação e Conclusão 🚀
A API Yarncom foi implantada em um ambiente de produção utilizando o Render e MongoDB Atlas. O processo de implantação envolveu a configuração de variáveis de ambiente, a configuração do banco de dados e a deploy da aplicação.
Deploy no Render
O deploy da API no Render foi feito utilizando o comando `render deploy`. Isso criou um ambiente de produção com o nome `yarncom-api` e configurou o servidor para ouvir em `http://yarncom-api.onrender.com`.
render deploy
Configuração do Banco de Dados
A configuração do banco de dados foi feita utilizando o MongoDB Atlas. Foi criado um cluster e configurado o usuário e senha para acesso ao banco de dados.
// Configuração do banco de dados
const mongoose = require('mongoose');
mongoose.connect('mongodb+srv://usuário:senha@cluster.mongodb.net/yarncom', {
useNewUrlParser: true,
useUnifiedTopology: true
});
Lições Aprendidas
Essa experiência me ensinou a importância da persistência e testes rigorosos no desenvolvimento de APIs de produção. Além disso, aprendi a importância de configurar o ambiente de produção corretamente e de testar a aplicação antes de implantá-la.
A API Yarncom foi um projeto desafiador, mas também muito gratificante. Aprendi muito sobre sistemas de gerenciamento de conteúdo e segurança de dados, e estou ansioso para aplicar essas habilidades em projetos futuros.
Se você está interessado em ver a API Yarncom em ação, pode acessá-la em https://yarncom-api.onrender.com/blogs.
Fonte de Referência: dev.to.
Curadoria e Adaptação: Redação Yassutaro Developers.