Features
Docs
CLI
Benchmarks
Examples

© 2024 MoroJs

gRPC Support

Build high-performance microservices with native gRPC support. Support for unary, streaming, and bidirectional RPC calls with Protocol Buffers.

gRPC That Just Works

Build high-performance microservices with gRPC.
Unary, streaming, and bidirectional calls. Protocol Buffers included.

It's This Simple

Set up gRPC with one call

typescript

1import { createApp } from '@morojs/moro';
2
3const app = 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:50051

Why gRPC Matters

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.

Without 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

Why It Makes Sense

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

Installation

typescript

1# Install gRPC dependencies
2npm install @grpc/grpc-js @grpc/proto-loader

Basic gRPC Server

typescript

1import { createApp } from '@morojs/moro';
2
3const app = 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

Proto File Example

typescript

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

Unary RPC

typescript

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});

Server Streaming RPC

typescript

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}

Bidirectional Streaming RPC

typescript

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

Creating a Client

typescript

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);

Server Streaming Call

typescript

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

Token-Based Authentication

typescript

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});

Role-Based Access

typescript

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

Call Types

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

Next Steps