Protocols
gRPC Support
Build high-performance microservices with native gRPC support. Unary, streaming, and bidirectional RPC calls with Protocol Buffers.
Overview
Without proper gRPC support, you're manually setting up servers, handling Protocol Buffers, and managing streaming. With MoroJS, you get all of that automatically. Traditional gRPC setup requires complex configuration. We handle that automatically.
1import { createApp } from '@morojs/moro';
2
3const app = await createApp();
4
5// Configure gRPC
6app.grpcInit({
7 port: 50051,
8 adapter: 'grpc-js',
9 enableHealthCheck: true
10});
11
12// Register a service
13await app.grpcService('./proto/users.proto', 'UserService', {
14 GetUser: async (call, callback) => {
15 const user = await db.users.findById(call.request.id);
16 callback(null, user);
17 }
18});
19
20app.listen(3000);
21// HTTP: http://localhost:3000
22// gRPC: localhost:50051Without gRPC Support
- Manual gRPC server setup
- Complex Protocol Buffer handling
- No built-in streaming support
- Manual authentication setup
With MoroJS
- One-call gRPC setup
- Automatic Protocol Buffer handling
- Built-in streaming support
- Integrated authentication
Unary
Single request/response - REST-like operations
Server Streaming
Single request, stream responses - Data feeds
Client Streaming
Stream requests, single response - File uploads
Bidirectional
Stream both directions - Chat, real-time
How It Works
gRPC is a high-performance RPC framework that uses Protocol Buffers for serialization. MoroJS provides native gRPC support with automatic Protocol Buffer handling, streaming support, and integrated authentication. You define services in .proto files and implement handlers in your application.
Quick Start
1# Install gRPC dependencies
2npm install @grpc/grpc-js @grpc/proto-loader1import { createApp } from '@morojs/moro';
2
3const app = await createApp();
4
5// Configure gRPC - synchronous, no await needed!
6app.grpcInit({
7 port: 50051,
8 host: '0.0.0.0',
9 adapter: 'grpc-js',
10 enableHealthCheck: true,
11 enableReflection: true
12});
13
14// Register a service
15await app.grpcService('./proto/users.proto', 'UserService', {
16 GetUser: async (call, callback) => {
17 const user = await db.users.findById(call.request.id);
18 callback(null, user);
19 },
20 ListUsers: async (call) => {
21 const users = await db.users.findAll();
22 for (const user of users) {
23 call.write(user);
24 }
25 call.end();
26 }
27});
28
29// Start both HTTP and gRPC servers
30app.listen(3000, () => {
31 console.log('HTTP: http://localhost:3000');
32 console.log('gRPC: localhost:50051');
33});Service Definition
1syntax = "proto3";
2
3package user;
4
5service UserService {
6 // Unary call
7 rpc GetUser (GetUserRequest) returns (User) {}
8
9 // Server streaming
10 rpc ListUsers (ListUsersRequest) returns (stream User) {}
11
12 // Client streaming
13 rpc CreateUsers (stream CreateUserRequest) returns (CreateUsersResponse) {}
14
15 // Bidirectional streaming
16 rpc Chat (stream ChatMessage) returns (stream ChatMessage) {}
17}
18
19message GetUserRequest {
20 string id = 1;
21}
22
23message User {
24 string id = 1;
25 string name = 2;
26 string email = 3;
27 int32 age = 4;
28}
29
30message ListUsersRequest {
31 int32 page = 1;
32 int32 limit = 2;
33}
34
35message CreateUserRequest {
36 string name = 1;
37 string email = 2;
38}
39
40message CreateUsersResponse {
41 int32 created = 1;
42 repeated string ids = 2;
43}
44
45message ChatMessage {
46 string user_id = 1;
47 string message = 2;
48 int64 timestamp = 3;
49}Server Implementation
1await app.grpcService('./proto/users.proto', 'UserService', {
2 GetUser: async (call, callback) => {
3 try {
4 const { id } = call.request;
5
6 // Fetch from database
7 const user = await db.users.findById(id);
8
9 if (!user) {
10 return callback({
11 code: grpc.status.NOT_FOUND,
12 message: 'User not found'
13 });
14 }
15
16 callback(null, user);
17 } catch (error) {
18 callback({
19 code: grpc.status.INTERNAL,
20 message: error.message
21 });
22 }
23 }
24});1{
2 ListUsers: async (call) => {
3 const { page, limit } = call.request;
4
5 try {
6 const users = await db.users
7 .find()
8 .skip(page * limit)
9 .limit(limit);
10
11 // Stream each user
12 for (const user of users) {
13 call.write({
14 id: user.id,
15 name: user.name,
16 email: user.email,
17 age: user.age
18 });
19 }
20
21 // End stream
22 call.end();
23 } catch (error) {
24 call.destroy(error);
25 }
26 }
27}1{
2 Chat: async (call) => {
3 const userId = call.metadata.get('user-id');
4
5 // Receive messages
6 call.on('data', (message) => {
7 console.log(`User ${userId}: ${message.message}`);
8
9 // Broadcast to other clients
10 broadcastToRoom(message);
11
12 // Echo back confirmation
13 call.write({
14 user_id: 'system',
15 message: `Message received: ${message.message}`,
16 timestamp: Date.now()
17 });
18 });
19
20 call.on('end', () => {
21 call.end();
22 });
23
24 call.on('error', (error) => {
25 console.error('Chat error:', error);
26 });
27 }
28}Client Usage
1// Create a gRPC client
2const client = await app.createGrpcClient(
3 './proto/users.proto',
4 'UserService',
5 'localhost:50051',
6 {
7 credentials: 'insecure' // or provide TLS credentials
8 }
9);
10
11// Use the client
12const user = await new Promise((resolve, reject) => {
13 client.GetUser({ id: '123' }, (error, response) => {
14 if (error) reject(error);
15 else resolve(response);
16 });
17});
18
19console.log(user.name);1const call = client.ListUsers({ page: 0, limit: 10 });
2
3call.on('data', (user) => {
4 console.log('Received user:', user.name);
5});
6
7call.on('end', () => {
8 console.log('Stream ended');
9});
10
11call.on('error', (error) => {
12 console.error('Stream error:', error);
13});Authentication & Middleware
1import { grpcAuth, extractTokenFromMetadata } from '@morojs/moro';
2
3// Server side
4await app.grpcService('./proto/users.proto', 'UserService', {
5 GetUser: grpcAuth({
6 extractToken: extractTokenFromMetadata,
7 verifyToken: async (token) => {
8 return await verifyJWT(token, process.env.JWT_SECRET);
9 }
10 })(async (call, callback) => {
11 console.log('Authenticated user:', call.user);
12 const user = await db.users.findOne({ id: call.request.id });
13 callback(null, user);
14 })
15});
16
17// Client side
18const metadata = new grpc.Metadata();
19metadata.add('authorization', `Bearer ${token}`);
20
21client.GetUser({ id: '123' }, metadata, (error, response) => {
22 // ...
23});1import { grpcRequireRole } from '@morojs/moro';
2
3await app.grpcService('./proto/users.proto', 'UserService', {
4 // Requires 'admin' role
5 DeleteUser: grpcRequireRole('admin')(async (call, callback) => {
6 await db.users.deleteOne({ id: call.request.id });
7 callback(null, { success: true });
8 })
9});Features
Core Features
- Proto-based service definitions
- Unary, server streaming, client streaming, bidirectional
- Authentication and middleware support
- Built-in health check service
- Server reflection for debugging
- TLS/SSL support