Skip to content
/ groa Public

Expressive gRPC middleware framework for Node.js

License

Notifications You must be signed in to change notification settings

GroaJS/groa

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

49 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Groa

Expressive gRPC middleware framework for Node.js. It provides the same style of middleware system and APIs many developers are familiar with which is similar to Koa 2.

NPM

Requirement

Node.js v7.6+ is required, the middleware system of Gora is based on async function.

Installation

Install via NPM:

npm install groa --save

Getting Started

The same way with Koa to implement your first gRPC server:

const Groa = require('groa');

const app = new Groa();

// Add proto file
app.addProto(__dirname + '/example.proto');

// Add middleware
app.use(async (ctx, next) => {

	// response
	ctx.body = ctx.req.body;
});

app.listen(50051, () => {
	console.log('Listening on port 50051');
});

example.proto

syntax = "proto3";

package example.foo;

service Example1 {
	rpc Ping(Ping) returns (Pong) {}
}

message Ping {
	string content = 1;
}

message Pong {
	string content = 1;
}

Send Data as a Stream

Implement streaming method is quite easy that writing to Stream object of body directly.

const Groa = require('groa');

const app = new Groa();

// Add proto file
app.addProto(__dirname + '/stream.proto');

const delay = (interval) => {
	return new Promise((resolve) => {
		setTimeout(resolve, interval);
	});
}

// Add middleware
app.use(async (ctx, next) => {

	// send a message
	ctx.body.write({
		timestamp: new Date()
	});
	
	// delay 1 second
	await delay(1000);
	
	// send a message
	ctx.body.write({
		timestamp: new Date()
	});
	
	// delay 1 second
	await delay(1000);
	
	// complete
	ctx.body.end();
});

app.listen(50051, () => {
	console.log('Listening on port 50051');
});

stream.proto

syntax = "proto3";

package example.foo;

service Example1 {
	rpc receive(ReceiveRequest) returns (stream ReceiveResponse) {};
}

message ReceiveRequest {
}

message ReceiveResponse {
	string timestamp = 1;
}

Receive Data from Stream

When input is a stream, ctx.req.body will be a stream object for receiving data. Besides, ctx.body contains the same stream object with ctx.req.body if output is stream as well.

const Groa = require('groa');

const app = new Groa();

// Add proto file
app.addProto(__dirname + '/stream.proto');

// Add middleware
app.use(async (ctx, next) => {

	// Alias as ctx.body for input stream
	ctx.req.body.on('data', (data) => {
		console.log(data);
		
		// Send the same data back to client
		ctx.body.write(data);
	});
});

app.listen(50051, () => {
	console.log('Listening on port 50051');
});

stream.proto

syntax = "proto3";

package example.foo;

service Example1 {
	rpc receive(stream ReceiveRequest) returns (stream ReceiveResponse) {};
}

message ReceiveRequest {
	string timestamp = 1;
}

message ReceiveResponse {
	string timestamp = 1;
}

Status Code and Error Message

You can set status code and message when problem occurring for a request, the following is status code of gRPC Groa supported:

  • OK: 0
  • CANCELLED: 1
  • UNKNOWN: 2
  • INVALID_ARGUMENT: 3
  • DEADLINE_EXCEEDED: 4
  • NOT_FOUND: 5
  • ALREADY_EXISTS: 6
  • PERMISSION_DENIED: 7
  • RESOURCE_EXHAUSTED: 8
  • FAILED_PRECONDITION: 9
  • ABORTED: 10
  • OUT_OF_RANGE: 11
  • UNIMPLEMENTED: 12
  • INTERNAL: 13
  • UNAVAILABLE: 14
  • DATA_LOSS: 15
  • UNAUTHENTICATED: 16

Usage:

ctx.status = Groa.status.ABORTED;
ctx.message = 'Something\'s wrong'

Or you can throw an error:

ctx.throw('wrong'); // UNKNOWN if no status code
ctx.throw(Application.status.OUT_OF_RANGE);
ctx.throw(Application.status.OUT_OF_RANGE, 'OUT OF RANGE!!!');

Middlewares

Using Groa to build a Client with Promise-style functions

Groa provide a Client class which provides Promise-style functions to make client much easier in ES6.

const { Client } = require('groa');

const client = new Client('0.0.0.0', 50051);

const main = async () => {

	// Loading definition file
	await client.loadProto(__dirname + '/example.proto');
	
	// Get service defnined
	let Example1 = client.getService('example.foo.Example1');
	
	// call
	let ret = await Example1.ping({
		content: 'hello'
	});

	console.log(ret);
};

main();

TODO

  • Need more testcases
  • Support google.api.http to generate restful API automatically
  • Support SSL

License

Licensed under the MIT License

Authors

Copyright(c) 2017 Fred Chien(錢逢祥) <[email protected]>

About

Expressive gRPC middleware framework for Node.js

Resources

License

Stars

Watchers

Forks

Packages

No packages published