Construindo três APIs em um final de semana: .NET, Python e Node.js
No último final de semana, me desafiei a construir a mesma API Biblioteca, utilizando três linguagens diferentes: .NET, Python e Node.js. A ideia era entender as diferenças entre as tecnologias e explorar como cada stack lida com banco de dados, organização do código e boas práticas.
Além disso, adicionei Docker para facilitar a execução nas versões .NET e Python, enquanto na API Node.js implementei testes automatizados com Jest e logs estruturados com Winston.
Para testar e documentar as APIs, utilizei Swagger no .NET e no Python, e Postman no Node.js, cada um com suas particularidades.
Neste artigo, compartilho como foi a experiência, as diferenças entre cada implementação e os desafios encontrados.
🔧 Tecnologias Utilizadas
Para garantir que todas as APIs tivessem a mesma estrutura e funcionalidades, utilizei as seguintes tecnologias em cada uma delas:
🟣 API Biblioteca com .NET
- ASP.NET Core — Framework para construção da API
- Entity Framework Core — ORM para interagir com PostgreSQL
- PostgreSQL — Banco de dados relacional
- Swagger — Documentação interativa da API
- Docker — Containerização da aplicação
🟡 API Biblioteca com Python
- FastAPI — Framework rápido e assíncrono para APIs
- SQLAlchemy — ORM para PostgreSQL
- Alembic — Ferramenta para controle de migrações
- Swagger — Documentação automática via OpenAPI
- Docker — Containerização da aplicação
🟢 API Biblioteca com Node.js
- Express — Framework para construção da API
- Sequelize — ORM para PostgreSQL
- Jest e Supertest — Testes automatizados
- Winston — Logging estruturado
- Postman — Testes e validação manual dos endpoints
⚖️ Comparação Entre as Implementações
Cada linguagem/framework tem suas particularidades, e a experiência de implementação variou bastante entre elas.
🟣 .NET — A Mais Desafiadora
A API em .NET foi, sem dúvida, a mais complexa de implementar. O Entity Framework Core funciona muito bem, mas exige um certo domínio do ciclo de vida das migrações e da configuração do banco. Além disso, a estrutura do projeto demanda mais código boilerplate em comparação com as outras linguagens.
Outra dificuldade foi a configuração do Docker, que exigiu ajustes finos para garantir que a aplicação subisse corretamente e conseguisse se conectar ao PostgreSQL dentro do container. No final, a API ficou robusta e bem estruturada, mas definitivamente levou mais tempo para ser concluída.
📌 Testes e Documentação:
Aqui, utilizei Swagger para gerar a documentação da API automaticamente. O Swagger é uma ferramenta que permite testar endpoints diretamente no navegador e visualizar todas as rotas disponíveis. Ele é especialmente útil em APIs mais formais, pois melhora a experiência de uso para outros desenvolvedores.
Swagger
🟡 Python — Facilidade com FastAPI, Dificuldade com Alembic
O FastAPI tornou o desenvolvimento muito rápido e fluido. A parte de roteamento, validação e documentação automática via Swagger são grandes vantagens.
No entanto, tive algumas dificuldades com o Alembic, que é a ferramenta de migração de banco para o SQLAlchemy. Configurar as migrações corretamente e garantir que as tabelas estavam sendo criadas da maneira esperada exigiu um tempo extra de pesquisa e tentativa e erro.
A adição do Docker foi bem mais tranquila do que no .NET, pois o Python tem uma abordagem mais direta para a execução dentro de containers.
API rodando no Docker
📌 Criação do Projeto Usando Shell Script:
Para acelerar a configuração inicial do projeto, utilizei um script Shell, que automaticamente criou a estrutura de diretórios e arquivos necessários. Isso me permitiu ganhar tempo e padronizar o desenvolvimento.
📌 Testes e Documentação:
Assim como no .NET, o FastAPI gera a documentação interativa automaticamente via Swagger.
🟢 Node.js — A Implementação Mais Simples
A API em Node.js foi a mais rápida e fácil de implementar. O Express facilita a criação de endpoints, e o Sequelize permite interagir com o PostgreSQL sem grandes dificuldades.
Diferente das outras duas versões, não utilizei Docker nesta implementação, pois foquei mais na parte de testes e logging.
📌 Criação do Projeto Usando Shell Script
Assim como na API Python, utilizei um script Shell para gerar automaticamente os diretórios e arquivos principais da API Node.js. Isso facilitou bastante a organização inicial do código.
📌 Minha Primeira Experiência com Logging Estruturado (Winston)
Uma das partes mais interessantes dessa implementação foi configurar logging estruturado com Winston. Até então, eu costumava usar apenas console.log()
para registrar eventos na aplicação, mas o Winston oferece uma solução muito mais organizada.
Com o Winston, configurei logs para três níveis principais:
✅ info — Informações gerais, como requisições bem-sucedidas.
⚠️ warn — Avisos, como tentativas de buscar livros que não existem.
❌ error — Erros críticos na aplicação.
Além de exibir os logs no terminal, o Winston também os salva em arquivos dentro da pasta logs/
, o que facilita a depuração e a análise posterior.
Exemplo de saída de logs:
2025-02-24 14:00:01 [INFO]: Servidor rodando na porta 8000
2025-02-24 14:00:05 [INFO]: Lista de livros retornada com sucesso.
2025-02-24 14:00:10 [WARN]: Livro ID 999 não encontrado.
2025-02-24 14:00:15 [ERROR]: Erro ao buscar livro ID 2: Conexão perdida com o banco.
Logs no terminal
Logs salvos no documento de logs
Implementar essa funcionalidade foi uma grande evolução no meu processo de desenvolvimento, e com certeza pretendo aplicar logs estruturados em projetos futuros.
📌 Minha Primeira Experiência com Testes Automatizados (Jest e Supertest):
Outra novidade para mim foi a implementação de testes automatizados. Sempre utilizei ferramentas como Postman para testar APIs manualmente, mas dessa vez resolvi adicionar Jest e Supertest para garantir que as principais funcionalidades estivessem funcionando corretamente.
Criei um teste para verificar se a rota GET /api/livros
retorna corretamente a lista de livros no banco de dados. Eis um exemplo do código:
const request = require('supertest');
const app = require('../app');
describe('GET /api/livros', () => {
it('deve retornar uma lista de livros', async () => {
const response = await request(app).get('/api/livros');
expect(response.statusCode).toBe(200);
expect(Array.isArray(response.body)).toBeTruthy();
});
});
Rodar os testes foi algo bem satisfatório, pois agora eu consigo garantir que a API está funcionando automaticamente, sem precisar fazer testes manuais sempre que altero algo.
Exemplo de saída dos testes:
PASS tests/app.test.js
GET /api/livros
✓ deve retornar uma lista de livros (275 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Teste
Com essa implementação, aprendi a importância dos testes automatizados, pois agora qualquer mudança no código pode ser validada instantaneamente, sem risco de quebrar funcionalidades sem perceber.
📌 Testes e Documentação:
Nesta API, ao invés de utilizar Swagger, optei por testar os endpoints manualmente no Postman. O Postman é uma ferramenta extremamente útil para validar APIs em tempo real e simular diferentes tipos de requisições.
A principal diferença entre Swagger e Postman é que o Swagger gera a documentação automaticamente dentro da própria aplicação, enquanto o Postman exige a criação manual dos testes. No entanto, o Postman é mais flexível e permite salvar e organizar os testes de forma mais detalhada.
📊 Conclusão
Foi um desafio muito interessante construir a mesma API em três tecnologias diferentes. Cada stack tem seus pontos fortes e desafios:
✅ .NET — Robusto, mas exige mais esforço inicial.
✅ Python — Rápido de desenvolver, mas pode ter dificuldades com migrações de banco.
✅ Node.js — O mais simples de implementar, com fácil integração de testes e logging.
😎Você pode ver o código de todas as APIs no meu Site: www.eduardolentz.com.br
Agora quero saber: Qual dessas tecnologias você mais gosta para construir APIs? 🚀
. . . . . . . .
Eduardo O. Lentz
💻 Portfolio | 🔗 LinkedIn | 📂 GitHub | 📝 Medium | 📸 Instagram