Microsserviços em JavaScript: arquitetura e prática para Node.js

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course
```html

Microsserviços em JavaScript: arquitetura e prática



A arquitetura de microsserviços (MSA) tornou-se o padrão de facto para construir aplicações complexas, escaláveis e tolerantes a falhas. Ao contrário do monolito, onde todo o código está ligado em um único processo, os microsserviços dividem o sistema em serviços pequenos e independentes. JavaScript, especificamente a plataforma Node.js, devido ao seu modelo orientado a eventos e ao seu enorme ecossistema, é uma excelente escolha para implementar microsserviços. Neste artigo, vamos analisar os princípios-chave da arquitetura, escrever alguns serviços funcionais e considerar os aspetos práticos da sua interação.



Princípios fundamentais da arquitetura de microsserviços



Antes de escrever código, é importante entender o que torna um microsserviço um "microsserviço". Os princípios fundamentais são:



  • Responsabilidade Única (Single Responsibility): Cada serviço resolve uma tarefa de negócio específica (por exemplo, apenas autenticação ou apenas gestão de pedidos).
  • Independência: Os serviços são desenvolvidos, testados e implantados independentemente uns dos outros.
  • Isolamento de dados: Cada serviço tem a sua própria base de dados. Não existe um repositório comum.
  • Baixo Acoplamento (Loose Coupling): Os serviços comunicam através da rede (API), e não através de chamadas diretas de funções.
  • Tolerância a Falhas: A falha de um serviço não deve derrubar todo o sistema.


Node.js é ideal para estas tarefas devido à sua natureza não bloqueante e assíncrona, o que é crítico quando há um grande número de chamadas de rede entre serviços.



Prática: Criando dois microsserviços simples



Vamos escrever dois serviços simples em Express.js: User Service (gestão de utilizadores) e Order Service (gestão de pedidos).



1. User Service (serviço de utilizadores)

Crie o ficheiro user-service/server.js:



const express = require('express');const app = express();app.use(express.json());

const users = [{ id: 1, name: 'Alice', email: 'alice@example.com' }];

app.get('/users/:id', (req, res) => { const user = users.find(u => u.id === parseInt(req.params.id)); if (!user) return res.status(404).json({ error: 'User not found' }); res.json(user);});

app.listen(3001, () => console.log('User Service running on port 3001'));


2. Order Service (serviço de pedidos)

Crie o ficheiro order-service/server.js:



const express = require('express');const app = express();app.use(express.json());

const orders = [ { id: 1, userId: 1, product: 'Laptop', amount: 1500 }];

app.get('/orders/user/:userId', (req, res) => { const userOrders = orders.filter(o => o.userId === parseInt(req.params.userId)); res.json(userOrders);});

app.listen(3002, () => console.log('Order Service running on port 3002'));


Agora temos dois serviços independentes, a funcionar em portas diferentes. Esta é a base da arquitetura de microsserviços.



Interação entre serviços: REST e Message Broker



Os serviços precisam de comunicar. Vamos considerar duas abordagens principais.



3.1 Interação síncrona (REST API)

Um serviço chama diretamente a API de outro. Por exemplo, para obter pedidos com o nome do utilizador, vamos criar um API Gateway ou um serviço compositor.



// api-gateway.jsconst axios = require('axios');

app.get('/users/:id/orders', async (req, res) => { try { const userResponse = await axios.get(`http://localhost:3001/users/${req.params.id}`); const ordersResponse = await axios.get(`http://localhost:3002/orders/user/${req.params.id}`); res.json({ user: userResponse.data, orders: ordersResponse.data }); } catch (error) { res.status(500).json({ error: 'Failed to fetch data' }); }});


3.2 Interação assíncrona (Message Broker)

Para um acoplamento mais fraco e melhor tolerância a falhas, os serviços podem comunicar através de um Message Broker (por exemplo, RabbitMQ, Kafka). Um serviço publica eventos e outros serviços os consomem.



// Event Publisher (User Service)const amqp = require('amqplib');

async function publishUserCreated(user) { const connection = await amqp.connect('amqp://localhost'); const channel = await connection.createChannel(); const exchange = 'user_events'; await channel.assertExchange(exchange, 'fanout', { durable: false }); channel.publish(exchange, '', Buffer.from(JSON.stringify(user))); console.log('Event published: User Created');}

// Event Consumer (Order Service)const amqp = require('amqplib');

async function consumeUserCreated() { const connection = await amqp.connect('amqp://localhost'); const channel = await connection.createChannel(); const exchange = 'user_events'; await channel.assertExchange(exchange, 'fanout', { durable: false }); const q = await channel.assertQueue('', { exclusive: true }); channel.bindQueue(q.queue, exchange, ''); channel.consume(q.queue, (msg) => { const user = JSON.parse(msg.content.toString()); console.log('Received User:', user); // Processar o evento (ex: criar um carrinho para o novo utilizador) }, { noAck: true });}


Conclusão



Os microsserviços em JavaScript (Node.js) oferecem uma forma poderosa de construir sistemas escaláveis e resilientes. Começamos com serviços pequenos e independentes, comunicando através de REST ou de um Message Broker. Lembre-se dos princípios: responsabilidade única, independência e isolamento de dados. Na prática, ferramentas como Docker, Kubernetes e sistemas de monitorização (Prometheus, Grafana) são frequentemente utilizadas para gerir o ciclo de vida e a saúde dos microsserviços. A arquitetura de microsserviços não é uma bala de prata, mas para sistemas complexos, é frequentemente a escolha certa.

```

Blogs

Book Recommendations