An implementation of a gRPC server in Erlang.
An implementation of the client side is also available: grpc_client.
The file "helloworld.proto" contains the specification for a simple "hello world" service:
syntax = "proto3";
package helloworld;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
Compile this file (from the Erlang shell):
1> grpc:compile("helloworld.proto").
This creates two files: helloworld.erl
and helloworld_server.erl
. The
first file contains code to encode and decode the gRPC messages (in
protocol buffer format). The second file contains type specifications for
the messages and a 'skeleton' for the RPC:
-spec 'SayHello'(Message::'HelloRequest'(), Stream::grpc:stream(), State::any()) ->
{'HelloReply'(), grpc:stream()} | grpc:error_response().
%% This is a unary RPC
'SayHello'(_Message, Stream, _State) ->
{#{}, Stream}.
Some code must be added to the skeleton to make it work:
'SayHello'(#{name := Name}, Stream, _State) ->
{#{message => "Hello, " ++ Name}, Stream}.
Now compile the modules and start the server (it will listen to port 10000):
2> c(helloworld).
3> c(helloworld_server).
4> grpc:start_server(hello, tcp, 10000, helloworld_server, []).
To see if it actually works you will need a grpc client. These exist in many languages (see grpc.io), but here we will use the erlang client (grpc_client):
1> grpc_client:compile("helloworld.proto").
2> c(helloworld).
3> c(helloword_client).
4> {ok, Connection} = grpc_client:connect(tcp, "localhost", 10000).
4> helloworld_client:'SayHello'(Connection, #{name => "World"}, []).
{ok,#{grpc_status => 0,
headers => #{<<":status">> => <<"200">>},
http_status => 200,
result => #{message => "Hello, World"},
status_message => <<>>,
trailers => #{<<"grpc-status">> => <<"0">>}}}
There are many more things you can do beyond what is shown in the simple example above - streaming from client to server, from server to client, both ways, adding metadata, compression, authentication ... - see the tutorial for more examples and further details, or the reference documentation for the details of the individual modules and functions.
gRPC uses erlang.mk as build tool. On Unix systems it can be built with:
make
make doc
can be used to generate documentation for the individual
modules from edoc comments in those modules.
See the erlang.mk documentation for an explanation on how the tool can be used in a Windows environment.
make ct
can be used to run a number of tests.
In the test directory there is an explanation how the software can be tested against the go gRPC implementation.
-
cowboy is used for the server.
-
gpb is used to encode and decode the protobuf messages. This is a 'build' dependency: gpb is required to create some modules from the .proto files, but the modules are self contained and don't have a runtime depedency on gpb.
The development of this application was championed by Holger Winkelmann of Travelping. Travelping also kindly provided sponsorship for the initial development. The development was primarily done by Willem de Jong with design input from Chandru Mullaparthi.
Apache 2.0