Seu carrinho está vazio no momento!

Introdução
Saudações, futuros mestres do desenvolvimento de APIs! Sou seu professor PHD e especialista mundial em APIs, e hoje vamos mergulhar em um tópico que é absolutamente central para a construção de qualquer aplicação Node.js moderna e escalável: os Sistemas de Módulos. Esta é a Aula 20, e o nível é básico, então prepare-se para aprender de forma prática e descomplicada.
Imagine o seguinte cenário no mundo real: você está construindo um grande prédio. Seria caótico tentar erguer a estrutura inteira com um único tipo de tijolo, sem divisões, sem a capacidade de encomendar peças pré-fabricadas, como janelas, portas ou sistemas elétricos. Cada especialista (encanador, eletricista, vidraceiro) precisa trabalhar em sua própria seção, mas com a capacidade de integrar seu trabalho ao resto da construção de forma harmoniosa.
No desenvolvimento de APIs e aplicações Node.js, os sistemas de módulos servem exatamente a esse propósito. Eles nos possibilitam organizar nosso código em arquivos separados e reutilizáveis, como se fossem as diferentes peças e especialistas do nosso prédio. Em vez de um único arquivo monolítico, temos módulos que cuidam de tarefas específicas (como lidar com rotas, conectar a um banco de dados, ou processar dados de usuários), tornando o código mais legível, manutenível e fácil de testar. Isso é vital para APIs modernas, pois elas precisam ser ágeis e robustas.
Nesta aula, você vai desenvolver e entender a diferença fundamental entre dois paradigmas de módulos no ecossistema Node.js/Express: o CommonJS (o modelo tradicional) e os ES Modules (o padrão mais recente do JavaScript). Você aprenderá a configurá-los, a importar e exportar funcionalidades, e a perceber o contexto em que cada um é mais apropriado. Isso é essencial para quem busca construir APIs eficazes e aderentes às melhores práticas do mercado.
Conceito Fundamental
Para compreendermos a fundo os sistemas de módulos, precisamos entender que eles são o mecanismo pelo qual o Node.js permite que você divida seu código em arquivos discretos. Cada arquivo pode ser considerado um “módulo” que encapsula funcionalidades específicas. Em vez de ter um código gigantesco e incontrolável em um único arquivo, você pode ter um módulo para as rotas da sua API, outro para a lógica de negócio, outro para a configuração do banco de dados, e assim por diante.
Existem, essencialmente, dois grandes “dialetos” ou terminologias corretas da indústria quando falamos de módulos no Node.js:
- CommonJS: Este é o sistema de módulos original e padrão do Node.js. Ele foi criado especificamente para ambientes de servidor para suprir a falta de um sistema de módulos nativo no JavaScript antes da padronização de ES Modules. No CommonJS, você usa
require()para importar módulos emodule.exportsouexportspara exportar funcionalidades. É um modelo síncrono, o que significa que, ao requisitar um módulo, o Node.js pausa a execução do script até que o módulo seja totalmente carregado.- Vantagens: Amplamente adotado em bases de código Node.js existentes, bem suportado por muitas ferramentas e bibliotecas mais antigas, e o carregamento síncrono pode ser mais simples de entender para alguns casos de uso.
- Desvantagens: Carregamento síncrono pode impactar a performance em cenários complexos, sintaxe diferente do padrão moderno do JavaScript (ES Modules).
- ES Modules (ESM): Também conhecidos como módulos JavaScript ou módulos ECMAScript, são o padrão oficial de módulos para JavaScript, tanto no navegador quanto no Node.js. Eles foram introduzidos no ES2015 (ES6). No ESM, você usa
importpara importar módulos eexportpara exportar funcionalidades. Ao contrário do CommonJS, o carregamento de módulos ESM é assíncrono por natureza, o que pode viabilizar otimizações e melhor desempenho. O Node.js começou a dar suporte total a ES Modules a partir da versão 12.- Vantagens: É o padrão oficial do JavaScript, o que facilita a transição entre ambientes (frontend/backend), suporta carregamento assíncrono e árvores de dependência estáticas (útil para otimizações como tree-shaking), e possui uma sintaxe mais moderna e limpa.
- Desvantagens: Requer configuração explícita no Node.js (via
"type": "module"nopackage.jsonou usando a extensão.mjs), e algumas bibliotecas mais antigas podem não ter suporte nativo a ESM, exigindo adaptações.
Em casos de uso reais em produção, você verá CommonJS predominantemente em projetos Node.js mais antigos ou legados. Já os ES Modules são a escolha preferida para novos projetos, especialmente aqueles que visam alinhar o backend com as práticas do frontend, ou que se beneficiam das otimizações de performance. A forma como isso se integra com outras tecnologias é direta: bibliotecas e frameworks como Express.js são projetados para funcionar perfeitamente com ambos os sistemas de módulos. A escolha impacta principalmente a sintaxe de como você organiza e relaciona seus arquivos de código.
Implementação Prática
Agora, vamos colocar as mãos na massa e ver como esses sistemas de módulos funcionam na prática. Vamos criar uma pequena aplicação Express.js para demonstrar a exportação e importação de rotas e funcionalidades com CommonJS e ES Modules.
Preparação do Ambiente
Primeiro, crie uma nova pasta para o seu projeto e inicialize um projeto Node.js. No seu terminal, execute:
mkdir modulos-aula20
cd modulos-aula20
npm init -y
npm install express --save
Isso criará um arquivo package.json e instalará o Express.js.
Exemplo 1: CommonJS (Padrão)
Vamos criar dois arquivos: app-cjs.js (o arquivo principal) e rotas-cjs.js (um módulo de rotas).
rotas-cjs.js
// rotas-cjs.js
// Este módulo exporta funções para lidar com diferentes rotas usando CommonJS.
const express = require('express'); // Importa o módulo Express, necessário para criar roteadores.
const router = express.Router(); // Cria uma nova instância de roteador Express.
// Define uma rota GET para o caminho base ('/').
router.get('/', (req, res) => {
// Envia uma resposta JSON simples para a requisição.
console.log('Requisição recebida na rota CommonJS principal.'); // Logging profissional para monitoramento.
res.json({ mensagem: 'Olá da API em CommonJS!', rota: '/' });
});
// Define uma rota GET para '/usuarios'.
router.get('/usuarios', (req, res) => {
// Envia uma resposta JSON com dados simulados de usuários.
console.log('Requisição recebida na rota CommonJS de usuários.'); // Logging para a rota de usuários.
const usuarios = [{ id: 1, nome: 'Alice' }, { id: 2, nome: 'Bruno' }];
res.json({ mensagem: 'Lista de usuários (CommonJS)', dados: usuarios });
});
// Define uma rota POST para '/produtos'.
// Esta rota simula a criação de um produto e exige um corpo JSON na requisição.
router.post('/produtos', (req, res) => {
const { nome, preco } = req.body; // Extrai nome e preco do corpo da requisição.
// Validação de entrada robusta: verifica se os campos essenciais estão presentes.
if (!nome || !preco) {
console.error('Erro: Nome ou preço ausente na criação do produto CommonJS.'); // Log de erro.
// Retorna um status 400 (Bad Request) com uma mensagem de erro.
return res.status(400).json({ erro: 'Nome e preço são obrigatórios para criar um produto.' });
}
// Simula a criação de um novo produto com um ID fictício.
const novoProduto = { id: Date.now(), nome, preco };
console.log(Produto CommonJS criado: ${JSON.stringify(novoProduto)}); // Log de sucesso.
// Retorna um status 201 (Created) e os dados do novo produto.
res.status(201).json({ mensagem: 'Produto criado com sucesso (CommonJS)', produto: novoProduto });
});
// Exporta o objeto router para que ele possa ser usado em outros arquivos.
// Esta é a sintaxe de exportação padrão do CommonJS.
module.exports = router;
app-cjs.js
// app-cjs.js
// Arquivo principal da aplicação Express usando CommonJS.
const express = require('express'); // Importa o framework Express.
const bodyParser = require('body-parser'); // Importa o body-parser para lidar com JSON no corpo das requisições.
const cjsRoutes = require('./rotas-cjs'); // Importa o módulo de rotas CommonJS que acabamos de criar.
const app = express(); // Cria uma instância da aplicação Express.
const PORT = process.env.PORT || 3000; // Define a porta do servidor, padrão para 3000.
// Configurações enterprise básicas:
app.use(bodyParser.json()); // Habilita o Express a interpretar corpos de requisição como JSON.
app.use(express.urlencoded({ extended: true })); // Habilita o Express a interpretar dados de formulário.
// Adiciona o módulo de rotas importado à aplicação, prefixado com '/api-cjs'.
// Todas as rotas definidas em 'rotas-cjs.js' estarão disponíveis em /api-cjs/alguma-rota.
app.use('/api-cjs', cjsRoutes);
// Rota de fallback para qualquer caminho não encontrado.
app.use((req, res) => {
console.warn(Rota não encontrada: ${req.method} ${req.originalUrl}); // Logging de alerta para rotas inexistentes.
res.status(404).json({ erro: 'Recurso não encontrado (CommonJS).' });
});
// Inicia o servidor Express.
app.listen(PORT, () => {
console.log(Servidor CommonJS rodando em http://localhost:${PORT});
console.log(Teste: Acesse http://localhost:${PORT}/api-cjs ou http://localhost:${PORT}/api-cjs/usuarios);
});
Exemplo 2: ES Modules (Moderno)
Para usar ES Modules, precisamos fazer uma pequena alteração no package.json ou usar a extensão .mjs.
Configuração para ES Modules
Abra seu arquivo package.json e adicione a seguinte linha no nível superior do objeto JSON (logo abaixo do "name"):
{
"name": "modulos-aula20",
"version": "1.0.0",
"description": "",
"main": "app-cjs.js",
"type": "module", // <-- ADICIONE ESTA LINHA
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start-cjs": "node app-cjs.js",
"start-esm": "node app-esm.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.18.2"
}
}
Com "type": "module" , todos os arquivos .js na sua pasta serão tratados como ES Modules por padrão. Se você quiser que algum arquivo continue sendo CommonJS, deverá usar a extensão .cjs para ele (ex: app-cjs.cjs). Nosso app-cjs.js ainda funcionará porque o Node.js é inteligente, mas para ser explícito, você poderia renomeá-lo para app-cjs.cjs.
Vamos criar agora app-esm.js e rotas-esm.js:
rotas-esm.js
// rotas-esm.js
// Este módulo exporta funções para lidar com diferentes rotas usando ES Modules.
import express from 'express'; // Sintaxe 'import' para módulos ES.
const router = express.Router(); // Cria uma nova instância de roteador Express.
// Define uma rota GET para o caminho base ('/').
router.get('/', (req, res) => {
console.log('Requisição recebida na rota ES Modules principal.'); // Logging profissional.
res.json({ mensagem: 'Olá da API em ES Modules!', rota: '/' });
});
// Define uma rota GET para '/produtos'.
router.get('/produtos', (req, res) => {
console.log('Requisição recebida na rota ES Modules de produtos.'); // Logging para a rota de produtos.
const produtos = [{ id: 101, nome: 'Teclado' }, { id: 102, nome: 'Mouse' }];
res.json({ mensagem: 'Lista de produtos (ES Modules)', dados: produtos });
});
// Define uma rota PUT para '/usuarios/:id'.
// Esta rota simula a atualização de um usuário.
router.put('/usuarios/:id', (req, res) => {
const { id } = req.params; // Extrai o ID do usuário dos parâmetros da URL.
const { nome } = req.body; // Extrai o novo nome do corpo da requisição.
// Validação de entrada robusta: verifica se o nome está presente.
if (!nome) {
console.error(Erro: Nome ausente para atualização do usuário ${id} em ES Modules.); // Log de erro.
return res.status(400).json({ erro: 'O nome é obrigatório para atualizar o usuário.' });
}
// Simula a atualização de um usuário.
const usuarioAtualizado = { id: parseInt(id), nome }; // Converte o ID para número.
console.log(Usuário ES Modules atualizado: ${JSON.stringify(usuarioAtualizado)}); // Log de sucesso.
res.json({ mensagem: Usuário ${id} atualizado com sucesso (ES Modules), usuario: usuarioAtualizado });
});
// Exporta o objeto router.
// Esta é a sintaxe de exportação padrão dos ES Modules.
export default router;
app-esm.js
// app-esm.js
// Arquivo principal da aplicação Express usando ES Modules.
import express from 'express'; // Importa o Express usando sintaxe ES Modules.
// Note: body-parser é frequentemente integrado ao Express 4.16+, então pode ser omitido.
// Ou você pode importá-lo se preferir: import bodyParser from 'body-parser';
import esmRoutes from './rotas-esm.js'; // Importa o módulo de rotas ES Modules.
// É boa prática incluir a extensão do arquivo (.js, .mjs) ao importar módulos locais em ESM.
const app = express(); // Cria uma instância da aplicação Express.
const PORT = process.env.PORT || 3001; // Define uma porta diferente para o servidor ESM.
// Configurações enterprise básicas:
app.use(express.json()); // Usa o middleware embutido do Express para JSON.
app.use(express.urlencoded({ extended: true })); // Para dados de formulário.
// Adiciona o módulo de rotas importado à aplicação, prefixado com '/api-esm'.
app.use('/api-esm', esmRoutes);
// Rota de fallback para qualquer caminho não encontrado.
app.use((req, res) => {
console.warn(Rota não encontrada: ${req.method} ${req.originalUrl} (ES Modules)); // Logging de alerta.
res.status(404).json({ erro: 'Recurso não encontrado (ES Modules).' });
});
// Inicia o servidor Express.
app.listen(PORT, () => {
console.log(Servidor ES Modules rodando em http://localhost:${PORT});
console.log(Teste: Acesse http://localhost:${PORT}/api-esm ou http://localhost:${PORT}/api-esm/produtos);
});
Configurações Específicas para HostGator Plano M
Prezados alunos, é relevante destacar um ponto crucial aqui. O HostGator Plano M é um ambiente de hospedagem compartilhada, otimizado primariamente para PHP e Apache. Rodar Node.js diretamente em um ambiente como este pode ser um desafio significativo e não é o cenário ideal para aplicações Node.js em produção.
Os sistemas de módulos (CommonJS e ES Modules) são características do runtime do Node.js, não dependem diretamente da configuração do servidor web (Apache, Nginx). Se o seu HostGator Plano M permitisse a execução de Node.js (o que geralmente requer um plano VPS ou dedicado, ou uma configuração manual complexa como o uso de Passenger ou um proxy .htaccess para uma porta específica), a forma como você importa e exporta módulos seria a mesma demonstrada acima, pois isso é uma funcionalidade interna do Node.js.
Para um ambiente de produção enterprise com Node.js, a recomendação é utilizar um Servidor Privado Virtual (VPS), plataformas como AWS, Azure, Google Cloud, ou serviços especializados em hospedagem Node.js como Heroku, Vercel ou Railway. Nestes ambientes, você teria controle total sobre a versão do Node.js, as configurações de sistema e a execução da sua aplicação, tornando a implementação de CommonJS ou ES Modules transparente.
Em suma, a escolha entre CommonJS e ES Modules se define no seu package.json ("type": "module") ou nas extensões dos arquivos (.js vs .mjs ou .cjs), e o Node.js interpretará o código corretamente, independentemente do host, desde que ele suporte o ambiente Node.js.
Testes Básicos
Para testar nossas aplicações, adicione scripts ao seu package.json:
{
"name": "modulos-aula20",
"version": "1.0.0",
"description": "",
"main": "app-cjs.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start-cjs": "node app-cjs.js", // Script para iniciar a aplicação CommonJS
"start-esm": "node app-esm.js" // Script para iniciar a aplicação ES Modules
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.18.2",
"body-parser": "^1.20.2" // Adicione body-parser se não estiver já
}
}
Agora, no seu terminal:
# Para iniciar o servidor CommonJS
npm run start-cjs
Abra outro terminal para testar, ou use um cliente REST (Postman, Insomnia, curl)
📚 Informações da Aula
Curso: API Completo - Node.js & Express
Tempo estimado: 25 minutos
Pré-requisitos: JavaScript básico
Teste GET:
curl http://localhost:3000/api-cjs
curl http://localhost:3000/api-cjs/usuarios
Teste POST (CommonJS):
curl -X POST -H "Content-Type: application/json" -d '{"nome":"Laptop Gamer","preco":1500}' http://localhost:3000/api-cjs/produtos
Para iniciar o servidor ES Modules (em outra porta, então pode rodar em paralelo)
npm run start-esm
Teste GET:
curl http://localhost:3001/api-esm
curl http://localhost:3001/api-esm/produtos
Teste PUT (ES Modules):
curl -X PUT -H "Content-Type: application/json" -d '{"nome":"Carlos Silva"}' http://localhost:3001/api-esm/usuarios/3
Observe os logs no console para ver o funcionamento do logging profissional que implementamos e as mensagens de sucesso ou erro.
Exercício Hands-On
Excelente! Agora é sua vez de solidificar o conhecimento.
Desafio Prático
Seu desafio é o seguinte: crie um novo módulo chamado utilidades.js (ou utilidades.mjs para ES Modules e utilidades.cjs para CommonJS) que contenha duas funções simples:
- Uma função que retorne a data e hora atual formatada.
- Uma função que capitalize (torne a primeira letra maiúscula) uma string.
Em seguida, integre este módulo em ambas as suas aplicações (CommonJS e ES Modules) e use as funções em uma nova rota. Por exemplo, uma rota /data que exiba a data formatada, e uma rota /saudacao/:nome que capitalize o nome recebido e retorne uma saudação.
Solução Detalhada Passo a Passo
1. Crie o arquivo utilidades.js (para uso em ambos os contextos, usaremos a sintaxe de ES Modules e importaremos via import em app-esm.js e via dynamic import ou transpilação em app-cjs.js para simplificar, ou criaremos duas versões, uma .cjs e uma .mjs para ser mais claro para iniciantes). Para manter a clareza e o nível básico, faremos uma versão .cjs e uma .mjs.
utilidades.cjs (Para CommonJS)
// utilidades.cjs
// Módulo de utilidades usando CommonJS.
function obterDataHoraAtual() {
const data = new Date();
// Formato de data e hora legível.
return data.toLocaleString('pt-BR', {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
}
function capitalizarString(str) {
if (!str || typeof str !== 'string') {
return ''; // Trata entradas inválidas.
}
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
}
// Exporta as funções usando CommonJS.
module.exports = {
obterDataHoraAtual,
capitalizarString
};
utilidades.mjs (Para ES Modules)
// utilidades.mjs
// Módulo de utilidades usando ES Modules.
export function obterDataHoraAtual() {
const data = new Date();
return data.toLocaleString('pt-BR', {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
}
export function capitalizarString(str) {
if (!str || typeof str !== 'string') {
return '';
}
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
}
// Em ES Modules, as exports são diretas na declaração da função,
// ou exportadas como um objeto no final (export { obterDataHoraAtual, capitalizarString };)
// No caso acima, usamos exportações nomeadas.
2. Integre em app-cjs.js e rotas-cjs.js
Atualize rotas-cjs.js para importar e usar as utilidades:
rotas-cjs.js (atualizado)
// rotas-cjs.js (Atualizado com utilidades)
const express = require('express');
const router = express.Router();
const { obterDataHoraAtual, capitalizarString } = require('./utilidades.cjs'); // Importa as utilidades CJS.
// ... (rotas existentes) ...
// Nova rota para data
router.get('/data', (req, res) => {
const dataHora = obterDataHoraAtual();
console.log(Requisição para data em CommonJS. Data: ${dataHora});
res.json({ mensagem: 'Data e Hora Atual (CommonJS)', dataHora });
});
// Nova rota para saudação com capitalização
router.get('/saudacao/:nome', (req, res) => {
const nomeOriginal = req.params.nome;
const nomeCapitalizado = capitalizarString(nomeOriginal);
console.log(Requisição para saudação em CommonJS. Nome original: ${nomeOriginal}, Capitalizado: ${nomeCapitalizado});
res.json({ mensagem: Olá, ${nomeCapitalizado}! Seja bem-vindo(a) (CommonJS). });
});
module.exports = router;
3. Integre em app-esm.js e rotas-esm.js
Atualize rotas-esm.js para importar e usar as utilidades:
rotas-esm.js (atualizado)
// rotas-esm.js (Atualizado com utilidades)
import express from 'express';
import { obterDataHoraAtual, capitalizarString } from './utilidades.mjs'; // Importa as utilidades ESM.
const router = express.Router();
// ... (rotas existentes) ...
// Nova rota para data
router.get('/data', (req, res) => {
const dataHora = obterDataHoraAtual();
console.log(Requisição para data em ES Modules. Data: ${dataHora});
res.json({ mensagem: 'Data e Hora Atual (ES Modules)', dataHora });
});
// Nova rota para saudação com capitalização
router.get('/saudacao/:nome', (req, res) => {
const nomeOriginal = req.params.nome;
const nomeCapitalizado = capitalizarString(nomeOriginal);
console.log(Requisição para saudação em ES Modules. Nome original: ${nomeOriginal}, Capitalizado: ${nomeCapitalizado});
res.json({ mensagem: Olá, ${nomeCapitalizado}! Seja bem-vindo(a) (ES Modules). });
});
export default router;
Como Testar e Validar o Resultado
1. Inicie o servidor CommonJS:
npm run start-cjs
Testes:
curl http://localhost:3000/api-cjs/datacurl http://localhost:3000/api-cjs/saudacao/joaocurl http://localhost:3000/api-cjs/saudacao/maria
2. Inicie o servidor ES Modules (em outro terminal):
npm run start-esm
Testes:
curl http://localhost:3001/api-esm/datacurl http://localhost:3001/api-esm/saudacao/pedrocurl http://localhost:3001/api-esm/saudacao/ana
Verifique as respostas JSON e os logs no terminal para confirmar que as funções foram executadas corretamente.
Troubleshooting dos Erros Mais Comuns
require is not definedouimport / exporterros em arquivos.js: Se você configurou"type": "module"nopackage.json, todos os arquivos.jssão ES Modules. Se tentar usarrequire()neles, terá um erro. Solução: useimport/exportou renomeie o arquivo para.cjs.Cannot use import statement outside a module(ES Modules): Isso significa que o Node.js está tratando seu arquivo como CommonJS, mas você está usando sintaxeimport. Solução: adicione"type": "module"ao seupackage.jsonou use a extensão.mjspara o arquivo.Cannot find module './utilidades'(CommonJS): Certifique-se de que o caminho do arquivoutilidades.cjsestá correto e que a extensão.cjsfoi especificada norequire().Cannot find module './utilidades.mjs'(ES Modules): Lembre-se que em ES Modules, é essencial incluir a extensão do arquivo (.mjsou.js) para módulos locais. O Node.js não faz a inferência automática como no CommonJS.- Servidor não inicia na porta esperada: Verifique se a porta não está em uso por outro processo (rode
netstat -ano | findstr :3000no Windows oulsof -i :3000no Linux/macOS) ou se você digitounpm run start-cjsounpm run start-esmcorretamente.
Próximos Passos Sugeridos
Parabéns por completar este exercício! Para aprofundar ainda mais seu domínio sobre sistemas de módulos, eu sugiro:
- Explorar Módulos Nativo do Node.js: Experimente importar módulos nativos como
path,fsouhttpusando ambas as sintaxes (require('path')vsimport path from 'path'). - Trabalhar com Módulos de Terceiros: Importe bibliotecas como
axiosoulodash(que geralmente suportam ambos os formatos) para ver como eles se integram. - Refatorar um Projeto Existente: Se você tiver um pequeno projeto Node.js em CommonJS, tente refatorá-lo para usar ES Modules, lidando com os desafios que podem surgir.
- Compreender o
package.jsonexportsfield: Para projetos mais avançados, este campo nopackage.jsonpermite definir como seu próprio pacote exporta módulos para serem consumidos por CommonJS ou ES Modules.
Este conhecimento é fundamental para você se tornar um desenvolvedor de APIs de alto nível, capaz de trabalhar com qualquer base de código e construir soluções robustas e performáticas. Continue praticando, e o domínio será seu!
🚀 Pronto para a próxima aula?
Continue sua jornada no desenvolvimento de APIs e domine Node.js & Express!