A lightweight, TypeScript-first gRPC mock server designed for testing. Easily create mock gRPC services from your
.protofiles without complex setup.
- π Zero Configuration - Get started in seconds with minimal setup
- π¦ TypeScript Support - Built with TypeScript, includes type definitions
- π§ Flexible - Support for single and multiple proto files with cross-package imports
- π§ͺ Test-Friendly - Perfect for unit and integration testing
- π― Simple API - Clean, intuitive interface
- π Async/Await - Modern Promise-based API
npm install @alenon/grpc-mock-serverOr with yarn:
yarn add @alenon/grpc-mock-serverCreate a mock server in just a few lines:
import { GrpcMockServer } from '@alenon/grpc-mock-server';
// Create server instance
const server = new GrpcMockServer();
// Define your service implementations
const implementations = {
GetUser: (call: any, callback: any) => {
callback(null, { name: 'John Doe', id: '123' });
}
};
// Add service from proto file
server.addService(
'./path/to/user.proto',
'user', // package name from proto
'UserService', // service name from proto
implementations
);
// Start the server
await server.start();
console.log(`Server running at: ${server.serverAddress}`);
// Don't forget to stop when done!
await server.stop();This example demonstrates the simplest use case with a single proto file.
example.proto:
syntax = "proto3";
package com.alenon.example;
service ExampleService {
rpc ex1 (ExampleRequest) returns (ExampleResponse) {}
}
message ExampleRequest {
string msg = 1;
}
message ExampleResponse {
string msg = 1;
}example.ts:
import { GrpcMockServer } from '@alenon/grpc-mock-server';
import * as grpc from '@grpc/grpc-js';
import * as proto_loader from '@grpc/proto-loader';
import { ProtoUtils } from '@alenon/grpc-mock-server';
async function example() {
const server = new GrpcMockServer();
// Define implementations
const implementations = {
ex1: (call: any, callback: any) => {
console.log('Received:', call.request.msg);
callback(null, { msg: 'Hello from mock server!' });
}
};
// Add service
server.addService(
__dirname + '/example.proto',
'com.alenon.example',
'ExampleService',
implementations
);
// Start server
await server.start();
console.log(`Server listening at: ${server.serverAddress}`);
// Create client and test
const pkgDef = grpc.loadPackageDefinition(
proto_loader.loadSync(__dirname + '/example.proto')
);
const proto = ProtoUtils.getProtoFromPkgDefinition('com.alenon.example', pkgDef);
const client = new proto.ExampleService(
server.serverAddress,
grpc.credentials.createInsecure()
);
// Make request
const response = await new Promise((resolve, reject) => {
client.ex1({ msg: 'Hello!' }, (error: any, response: any) => {
error ? reject(error) : resolve(response);
});
});
console.log('Response:', response);
await server.stop();
}
example().catch(console.error);When your proto files import from other packages, use an array of proto paths with includeDirs:
user.proto:
syntax = "proto3";
package user;
import "address.proto";
message User {
string name = 1;
common.Address address = 2;
}
service UserService {
rpc GetUser (UserRequest) returns (UserResponse);
}
message UserRequest {
string id = 1;
}
message UserResponse {
User user = 1;
}address.proto:
syntax = "proto3";
package common;
message Address {
string postal_code = 1;
string city = 2;
string country = 3;
}multi-proto-example.ts:
import { GrpcMockServer } from '@alenon/grpc-mock-server';
async function multiProtoExample() {
const server = new GrpcMockServer();
const implementations = {
GetUser: (call: any, callback: any) => {
callback(null, {
user: {
name: 'John Doe',
address: {
postal_code: '12345',
city: 'San Francisco',
country: 'USA'
}
}
});
}
};
// Use array of proto files with options
server.addService(
[
__dirname + '/user.proto',
__dirname + '/address.proto'
],
'user',
'UserService',
implementations,
{
includeDirs: [__dirname], // Required for imports
keepCase: true, // Preserve field names
longs: String, // Convert longs to strings
enums: String, // Convert enums to strings
defaults: true, // Include default values
oneofs: true // Handle oneof fields
}
);
await server.start();
// ... use server ...
await server.stop();
}Perfect for Jest or other testing frameworks:
import { GrpcMockServer, ProtoUtils } from '@alenon/grpc-mock-server';
import * as grpc from '@grpc/grpc-js';
import * as proto_loader from '@grpc/proto-loader';
describe('ExampleService Tests', () => {
let server: GrpcMockServer;
let client: any;
beforeAll(async () => {
server = new GrpcMockServer();
server.addService(
__dirname + '/example.proto',
'com.alenon.example',
'ExampleService',
{
ex1: (call: any, callback: any) => {
callback(null, { msg: 'Test response' });
}
}
);
await server.start();
// Setup client
const pkgDef = grpc.loadPackageDefinition(
proto_loader.loadSync(__dirname + '/example.proto')
);
const proto = ProtoUtils.getProtoFromPkgDefinition('com.alenon.example', pkgDef);
client = new proto.ExampleService(
server.serverAddress,
grpc.credentials.createInsecure()
);
});
afterAll(async () => {
await server.stop();
});
it('should return response data', async () => {
const response = await new Promise((resolve, reject) => {
client.ex1({ msg: 'Test request' }, (error: any, response: any) => {
error ? reject(error) : resolve(response);
});
});
expect(response.msg).toBe('Test response');
});
});Main class for creating and managing mock gRPC servers.
new GrpcMockServer(serverAddress?: string)serverAddress(optional): Server address in formathost:port. Default:'127.0.0.1:50777'
Adds a gRPC service to the mock server.
Parameters:
protoPath:string | string[]- Path to proto file(s). Use array for multiple files with imports.pkgName:string- Package name as defined in your.protofile.serviceName:string- Service name as defined in your.protofile.implementations:object- Object mapping RPC method names to their implementations.- Each implementation is a function:
(call: any, callback: any) => void - Call
callback(null, response)for success - Call
callback(error)for errors
- Each implementation is a function:
protoLoadOptions(optional): Options for@grpc/proto-loader. Common options:includeDirs:string[]- Directories to search for imported proto fileskeepCase:boolean- Preserve field name casing (default:false)longs:Function- How to handle long values (e.g.,String)enums:Function- How to handle enum values (e.g.,String)defaults:boolean- Include default values (default:false)oneofs:boolean- Handle oneof fields (default:false)
Returns: GrpcMockServer (for method chaining)
Starts the mock server.
Returns: Promise<GrpcMockServer>
Stops the mock server gracefully.
Returns: Promise<GrpcMockServer>
Property: string - The address where the server is listening.
Property: grpc.Server - Access to the underlying gRPC server instance.
const server = new GrpcMockServer('localhost:50051');import * as grpc from '@grpc/grpc-js';
const implementations = {
GetUser: (call: any, callback: any) => {
if (!call.request.id) {
callback({ code: grpc.status.INVALID_ARGUMENT, message: 'ID required' });
return;
}
callback(null, { name: 'User', id: call.request.id });
}
};await new GrpcMockServer()
.addService(protoPath, pkgName, serviceName, impl1)
.addService(protoPath2, pkgName2, serviceName2, impl2)
.start();- Verify the
pkgNamematches exactly thepackagedeclaration in your.protofile - Check for typos and case sensitivity
- Verify the
serviceNamematches exactly the service name in your.protofile - Check for typos and case sensitivity
- Ensure
includeDirsincludes the directory containing imported proto files - Verify import paths in your proto files are correct relative to
includeDirs - Use
keepCase: trueif your proto uses snake_case field names
- Change the server address:
new GrpcMockServer('127.0.0.1:50778') - Ensure previous server instances are stopped
Check out the examples directory for complete working examples:
- Basic example - Single proto file
- Multi-proto example - Multiple proto files with imports
Run examples:
npm run example
npm run multi-proto-exampleContributions are welcome! Please feel free to submit a Pull Request.
MIT License - see LICENSE file for details.
- Always call
stop()after tests to clean up resources - Use
keepCase: trueif your proto files use snake_case naming - For complex proto structures, use
defaults: trueandoneofs: true - The server uses insecure credentials by default (perfect for testing)
Made with β€οΈ for the gRPC testing community