Leodario.com

Leodario.com – Tudo sobre Tecnologia

Aula 52 – API JavaScript, Node.js e Express – Schema Design – Normalization vs denormalization

Imagem destacada da aula de API

Introdução (3 min)

Imagine uma biblioteca. Se você organizar os livros sem nenhum critério, encontrá-los será um pesadelo. Normalização e desnormalização em APIs são como organizar essa biblioteca: podemos separá-la por autor, gênero e idioma (normalização) ou colocar os livros mais populares em uma seção especial para acesso rápido (desnormalização). Em APIs modernas, a forma como estruturamos os dados é essencial para o desempenho e a escalabilidade. Nesta aula, vamos aprender a aplicar esses conceitos em um contexto Node.js/Express, construindo um pequeno sistema de gerenciamento de autores e livros.

Conceito Fundamental (7 min)

Normalização é o processo de organizar os dados em tabelas separadas, eliminando redundâncias e garantindo a integridade dos dados. Pensando na nossa biblioteca, teríamos uma tabela para autores, outra para livros, e outra para gêneros, ligadas entre si. Já a desnormalização é o oposto: adicionamos redundâncias propositalmente para otimizar o desempenho das consultas. É como criar aquela seção de livros populares, repetindo alguns títulos para facilitar o acesso. Em produção, plataformas como o Twitter utilizam a desnormalização para exibir o feed de notícias rapidamente, enquanto bancos utilizam a normalização para garantir a consistência dos dados financeiros.

A normalização se integra com bancos de dados relacionais como PostgreSQL e MySQL. Suas vantagens incluem a redução de espaço em disco e a simplificação da manutenção dos dados. A desvantagem é a possível redução de desempenho em consultas complexas. A desnormalização, por sua vez, aumenta o desempenho de leitura, mas pode consumir mais espaço em disco e dificultar a atualização dos dados.

Implementação Prática (10 min)

const express = require('express');
const app = express();

// Simulação de banco de dados (em produção, use um banco de dados real) let autores = [{ id: 1, nome: 'Machado de Assis' }]; let livros = [{ id: 1, titulo: 'Dom Casmurro', autorId: 1 }];

// Rota normalizada (requer duas consultas) app.get('/api/v1/livros-normalizado/:id', (req, res) => { try { const livro = livros.find(l => l.id === parseInt(req.params.id)); if (!livro) return res.status(404).send('Livro não encontrado');

const autor = autores.find(a => a.id === livro.autorId); if (!autor) return res.status(500).send('Autor não encontrado (erro interno)'); // Erro de integridade

res.send({ livro, autor }); // Retorna livro e autor separadamente } catch (error) { console.error('Erro ao buscar livro normalizado:', error); // Logging profissional res.status(500).send('Erro interno do servidor'); } });

// Rota desnormalizada (uma única consulta) app.get('/api/v2/livros-desnormalizado/:id', (req, res) => { try { const livroDesnormalizado = livros.map(livro => { const autor = autores.find(a => a.id === livro.autorId); return { ...livro, autor: autor ? autor.nome : 'Autor Desconhecido' }; // Lidando com autor inexistente }).find(l => l.id === parseInt(req.params.id));

if (!livroDesnormalizado) return res.status(404).send('Livro não encontrado'); res.send(livroDesnormalizado); // Retorna livro com o nome do autor embutido } catch (error) { console.error('Erro ao buscar livro desnormalizado:', error); res.status(500).send('Erro interno do servidor'); }

});

app.listen(3000, () => console.log('Servidor rodando na porta 3000'));

npm install express
node seu_arquivo.js

Exercício Hands-On (5 min)

Crie uma nova rota /api/v2/autores/:id/livros que retorne todos os livros de um determinado autor usando a abordagem desnormalizada. Inclua o nome do autor em cada livro retornado.

Solução:

app.get('/api/v2/autores/:id/livros', (req, res) => {
  try {
    const autorId = parseInt(req.params.id);
    const autor = autores.find(a => a.id === autorId);

if (!autor) return res.status(404).send('Autor não encontrado');

const livrosDoAutor = livros.filter(l => l.autorId === autorId).map(livro => ({ ...livro, autor: autor.nome})); res.send(livrosDoAutor);

} catch (error) { console.error('Erro ao buscar livros do autor:', error); res.status(500).send('Erro interno do servidor'); } });

Para testar, faça uma requisição GET para http://localhost:3000/api/v2/autores/1/livros. Você deve receber uma lista de livros com o nome do autor incluído. Se encontrar erros, verifique o console do seu servidor para debugar. Como próximos passos, explore diferentes níveis de normalização e experimente com um banco de dados real.

🚀 Pronto para a próxima aula?

Continue sua jornada no desenvolvimento de APIs e domine Node.js & Express!

📚 Ver todas as aulas