gRPC
intro
Remote Procedure Call
RPC
// service1
export const sum = (a, b) => a + b;
// service2
import { sum } from 'service1';
console.log('result', sum(1, 2));
gRPC
Google Remote Procedure Call
service-to-service communication
Http2 + Protocol Buffers = gRPC
transport
message format
- Code generation
- High performance
- Strict specification
- Cross platform/languages
- Streaming
- Deadline/timeouts and cancellation
Strengths
哦所以就是換個方式 call API ?
對捏
啊幹嘛還要學一個別的方式 call API ?
沒錯。但就跟 graphQL 一樣
它一定還是有點東西才會彰顯它的價值所在
長知識
What is proto ?
config file -> .proto
syntax = "proto3";
package songs; // name space
import "google/protobuf/empty.proto";
message Song {
int32 id = 1;
string title = 2;
string artist = 3;
}
message Comment {
int32 song_id = 1;
string username = 2;
string body = 3;
}
service Songs {
rpc GetSong(google.protobuf.Empty) returns (Song) {};
rpc AddSongs(stream Song) returns (google.protobuf.Empty) {};
rpc GetChat(Song) returns (stream Comment) {};
rpc LiveChat(stream Comment) returns (stream Comment) {};
}
define schema
syntax = "proto3";
package songs; // name space
import "google/protobuf/empty.proto";
message Song {
int32 id = 1;
string title = 2;
string artist = 3;
}
message Comment {
int32 song_id = 1;
string username = 2;
string body = 3;
}
service Songs {
rpc GetSong(google.protobuf.Empty) returns (Song) {};
rpc AddSongs(stream Song) returns (google.protobuf.Empty) {};
rpc GetChat(Song) returns (stream Comment) {};
rpc LiveChat(stream Comment) returns (stream Comment) {};
}
filed type
method type
config file -> .proto
// source: songs.proto
/**
* @fileoverview
* @enhanceable
* @suppress {messageConventions} JS Compiler reports an error if a variable or
* field starts with 'MSG_' and isn't a translatable message.
* @public
*/
// GENERATED CODE -- DO NOT EDIT!
/* eslint-disable */
// @ts-nocheck
var jspb = require('google-protobuf');
var goog = jspb;
var global = Function('return this')();
var google_protobuf_empty_pb = require('google-protobuf/google/protobuf/empty_pb.js');
goog.object.extend(proto, google_protobuf_empty_pb);
goog.exportSymbol('proto.songs.Comment', null, global);
goog.exportSymbol('proto.songs.Song', null, global);
/**
* Generated by JsPbCodeGenerator.
* @param {Array=} opt_data Optional initial data array, typically from a
* server response, or constructed directly in Javascript. The array is used
* in place and becomes part of the constructed object. It is not cloned.
* If no data is provided, the constructed object will be empty, but still
* valid.
* @extends {jspb.Message}
* @constructor
*/
proto.songs.Song = function(opt_data) {
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
};
goog.inherits(proto.songs.Song, jspb.Message);
if (goog.DEBUG && !COMPILED) {
/**
* @public
* @override
*/
proto.songs.Song.displayName = 'proto.songs.Song';
}
compile it
code generation/cross platform
class SongsServer implements ISongsServer {
getSong(call: grpc.ServerUnaryCall<Empty, Song>, callback: sendUnaryData<Song>): void {
console.log(`${new Date().toISOString()} getSong`);
callback(null, getSong());
}
addSongs(call: grpc.ServerReadableStream<Song, Empty>, callback: sendUnaryData<Empty>): void {
console.log(`${new Date().toISOString()} addSongs`);
call.on('data', (song: Song) => {
addSong(song);
});
call.on('end', () => callback(null, new Empty()));
}
....
const server = new grpc.Server();
server.addService(SongsService, new SongsServer());
server.bindAsync(`localhost:${process.env.PORT}`,
grpc.ServerCredentials.createInsecure(), (err, port) => {
if (err) {
throw err;
}
console.log(`Listening on ${port}`);
server.start();
});
implement the server
DEMO
Restful vs graphQL vs gRPC
Usage scenarios
- Efficiently connecting polyglot services in microservices style architecture
- Connecting mobile devices, browser clients to backend services
- Generating efficient client libraries
End
gRPC
By Jay Chou
gRPC
- 369