O Node.js tem um ecossistema rico, mas seus próprios padrões que diferem bastante de linguagens síncronas. O event loop, streams, módulos, padrões assíncronos e o ecossistema npm têm suas próprias regras. Este post cobre os que aparecem repetidamente no desenvolvimento backend real.
TL;DR: Uma referência de Node.js cobrindo event loop, padrões assíncronos, streams, módulos, tratamento de erros e padrões do ecossistema.
Stack: Node.js, JavaScript
Nível: Intermediário
Tempo de leitura: ~15 min
Iniciar o projeto
npm init -y
npm install express typescript @types/express ts-node-dev
npx tsc --init
tsconfig.json mínimo
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true
}
}
Criar src/index.ts
import express, { Application, Request, Response } from 'express';
const app: Application = express();
const port: number = 3000;
app.get('/', (req: Request, res: Response) => {
res.send('Olá, mundo!');
});
app.listen(port, () => {
console.log(`Servidor rodando em http://localhost:${port}`);
});
Adicionar script dev ao package.json
{
"scripts": {
"dev": "ts-node-dev src/index.ts"
}
}
npm run dev
V1 – Rotas (personRoutes.ts)
import { Router } from 'express';
import { ListPerson } from '../../application/useCases/ListPerson/ListPerson';
const personRouter = Router();
const listPersonController = new ListPerson();
personRouter.get('/list-person', async (req, res) => {
try {
const people = await listPersonController.handle(req.body);
res.json(people);
} catch (error) {
res.status(500).send('Erro ao listar pessoas');
}
});
export { personRouter };
V2 – Controllers (ListPersonController.ts)
import { Request, Response } from 'express';
export class ListPersonController {
async handle(req: Request, res: Response): Promise {
return res.json({ message: 'Olá, Mundo!' });
}
}
V3 – Casos de Uso (ListPerson.ts)
import { IListPersonRequest } from "./protocols/IListPersonRequest";
import { IListPersonResponse } from "./protocols/IListPersonResponse";
class ListPerson {
async handle(inbound: IListPersonRequest): Promise> {
const returnList: Array = [];
returnList.push({ name: 'Allan' } as IListPersonResponse);
returnList.push({ name: 'Maradona' } as IListPersonResponse);
return returnList;
}
}
V4 – Repositório com TypeORM
npm install typeorm pg reflect-metadata
Crie o ormconfig.json, adicione o modelo de entidade do TypeORM, implemente o repositório concreto e injete-o no caso de uso pelo controller. O padrão é: controller injeta o repositório no caso de uso, e o caso de uso não sabe com qual banco está falando.
O que você construiu
Um backend Node.js em camadas com controllers, casos de uso e injeção de repositório, cobrindo os padrões que aparecem no código de produção real.
Próximos passos
- Entenda o event loop: código síncrono o bloqueia, então operações intensivas de CPU devem ir para worker threads ou processos filhos.
- Use Promise.all() para operações assíncronas independentes em paralelo, e Promise.allSettled() quando precisar dos resultados mesmo que algumas falhem.
- Nunca chame callback(err, result) de forma síncrona dentro de uma função assíncrona, isso cria bugs sutis de timing.
Dúvidas ou feedback? Me encontre no LinkedIn ou GitHub.