77[ ![ Total Download] ( https://img.shields.io/hexpm/dt/grpc.svg )] ( https://hex.pm/packages/elixir-grpc/grpc )
88[ ![ Last Updated] ( https://img.shields.io/github/last-commit/elixir-grpc/grpc.svg )] ( https://github.com/elixir-grpc/grpc/commits/master )
99
10- An Elixir implementation of [ gRPC] ( http ://www. grpc.io/ ) .
10+ ** gRPC Elixir** is a full-featured Elixir implementation of the [ gRPC] ( https ://grpc.io) protocol, supporting unary and streaming RPCs, interceptors, HTTP transcoding, and TLS. This version adopts a unified stream-based model for all types of calls .
1111
1212## Table of contents
1313
1414- [ Installation] ( #installation )
15- - [ Usage] ( #usage )
16- - [ Simple RPC] ( #simple-rpc )
17- - [ HTTP Transcoding] ( #http-transcoding )
18- - [ CORS] ( #cors )
19- - [ Start Application] ( #start-application )
15+ - [ Protobuf Code Generation] ( #protobuf-code-generation )
16+ - [ Server Implementation] ( #server-implementation )
17+ - [ Unary RPC using Stream API] ( #unary-rpc-using-stream-api )
18+ - [ Server-Side Streaming] ( #server-side-streaming )
19+ - [ Bidirectional Streaming] ( #bidirectional-streaming )
20+ - [ Application Startup] ( #application-startup )
21+ - [ Client Usage] ( #client-usage )
22+ - [ HTTP Transcoding] ( #http-transcoding )
23+ - [ CORS] ( #cors )
2024- [ Features] ( #features )
2125- [ Benchmark] ( #benchmark )
2226- [ Contributing] ( #contributing )
@@ -28,12 +32,16 @@ The package can be installed as:
2832``` elixir
2933def deps do
3034 [
31- {:grpc , " ~> 0.10" }
35+ {:grpc , " ~> 0.10" },
36+ {:protobuf , " ~> 0.14" }, # optional for import wellknown google types
37+ {:grpc_reflection , " ~> 0.1" } # optional enable grpc reflection
3238 ]
3339end
3440```
3541
36- ## Usage
42+ ## Protobuf Code Generation
43+
44+ Use ` protoc ` with [ protobuf elixir plugin] ( https://github.com/elixir-protobuf/protobuf ) or using [ protobuf_generate] ( https://hexdocs.pm/protobuf_generate/readme.html ) hex package to generate the necessary files.
3745
38461 . Write your protobuf file:
3947
@@ -53,51 +61,143 @@ message HelloReply {
5361}
5462
5563// The greeting service definition.
56- service Greeter {
57- // Greeting function
58- rpc SayHello (HelloRequest) returns (HelloReply) {}
64+ service GreetingServer {
65+ rpc SayUnaryHello (HelloRequest) returns (HelloReply) {}
66+ rpc SayServerHello (HelloRequest) returns (stream HelloReply) {}
67+ rpc SayBidStreamHello (stream HelloRequest) returns (stream HelloReply) {}
5968}
60-
6169```
6270
63- 2 . Then generate Elixir code from proto file as [ protobuf- elixir] ( https://github.com/elixir-protobuf/protobuf#usage ) :
71+ 2 . Compile protos (protoc + elixir plugin ):
6472
65- ``` shell
73+ ``` bash
6674protoc --elixir_out=plugins=grpc:./lib -I./priv/protos helloworld.proto
6775```
6876
69- In the following sections you will see how to implement gRPC server logic.
77+ ## Server Implementation
7078
71- ### ** Simple RPC**
79+ All RPC calls must be implemented using the stream-based API, even for unary requests.
7280
73- 1 . Implement the server side code like below and remember to return the expected message types.
81+ ### Unary RPC using Stream API
7482
7583``` elixir
76- defmodule Helloworld .Greeter .Server do
77- use GRPC .Server , service: Helloworld .Greeter .Service
84+ defmodule HelloworldStreams .Server do
85+ use GRPC .Server , service: Helloworld .GreetingServer .Service
86+
87+ alias GRPC .Stream
88+
89+ alias Helloworld .HelloRequest
90+ alias Helloworld .HelloReply
7891
79- @spec say_hello (Helloworld .HelloRequest .t , GRPC .Server .Stream .t ) :: Helloworld .HelloReply .t
80- def say_hello (request, _stream ) do
81- Helloworld .HelloReply .new (message: " Hello #{ request.name } " )
92+ @spec say_unary_hello (HelloRequest .t (), GRPC .Server .Stream .t ()) :: any ()
93+ def say_unary_hello (request, _materializer ) do
94+ GRPC .Stream .unary (request)
95+ |> GRPC .Stream .map (fn %HelloReply {} = reply ->
96+ %HelloReply {message: " [Reply] #{ reply.message } " }
97+ end )
98+ |> GRPC .Stream .run ()
8299 end
83100end
84101```
85102
86- 2 . Define gRPC endpoints
103+ ### Server-Side Streaming
87104
88105``` elixir
89- # Define your endpoint
90- defmodule Helloworld .Endpoint do
91- use GRPC .Endpoint
106+ def say_server_hello (request, materializer) do
107+ Stream .repeatedly (fn ->
108+ index = :rand .uniform (10 )
109+ %HelloReply {message: " [#{ index } ] Hello #{ request.name } " }
110+ end )
111+ |> Stream .take (10 )
112+ |> GRPC .Stream .from ()
113+ |> GRPC .Stream .run_with (materializer)
114+ end
115+ ```
92116
93- intercept GRPC .Server .Interceptors .Logger
94- run Helloworld .Greeter .Server
117+ ### Bidirectional Streaming
118+
119+ ``` elixir
120+ @spec say_bid_stream_hello (Enumerable .t (), GRPC .Server .Stream .t ()) :: any ()
121+ def say_bid_stream_hello (request, materializer) do
122+ output_stream =
123+ Stream .repeatedly (fn ->
124+ index = :rand .uniform (10 )
125+ %HelloReply {message: " [#{ index } ] Server response" }
126+ end )
127+
128+ GRPC .Stream .from (request, join_with: output_stream)
129+ |> GRPC .Stream .map (fn
130+ %HelloRequest {name: name} -> %HelloReply {message: " Welcome #{ name } " }
131+ other -> other
132+ end )
133+ |> GRPC .Stream .run_with (materializer)
95134end
96135```
136+ __ 💡__ The Stream API supports composable stream transformations via ` ask ` , ` map ` , ` run ` and others functions, enabling clean and declarative stream pipelines. For a complete list of available operators see [ here] ( lib/grpc/stream/operators.ex ) .
137+
138+ ## Application Startup
139+
140+ Add the server supervisor to your application's supervision tree:
141+
142+ ``` elixir
143+ defmodule Helloworld .Application do
144+ @ false
145+ use Application
146+
147+ @impl true
148+ def start (_type , _args ) do
149+ children = [
150+ GrpcReflection ,
151+ {
152+ GRPC .Server .Supervisor , [
153+ endpoint: Helloworld .Endpoint ,
154+ port: 50051 ,
155+ start_server: true ,
156+ # adapter_opts: [# any adapter-specific options like tls configuration....]
157+ ]
158+ }
159+ ]
160+
161+ opts = [strategy: :one_for_one , name: Helloworld .Supervisor ]
162+ Supervisor .start_link (children, opts)
163+ end
164+ end
165+ ```
166+
167+ # Client Usage
168+
169+ ``` elixir
170+ iex> {:ok , channel} = GRPC .Stub .connect (" localhost:50051" )
171+ iex> request = Helloworld .HelloRequest .new (name: " grpc-elixir" )
172+ iex> {:ok , reply} = channel |> Helloworld .GreetingServer .Stub .say_unary_hello (request)
173+
174+ # With interceptors
175+ iex> {:ok , channel} = GRPC .Stub .connect (" localhost:50051" , interceptors: [GRPC .Client .Interceptors .Logger ])
176+ .. .
177+ ```
178+
179+ Check the [ examples] ( examples ) and [ interop] ( interop ) directories in the project's source code for some examples.
180+
181+ ## Client Adapter and Configuration
182+
183+ The default adapter used by ` GRPC.Stub.connect/2 ` is ` GRPC.Client.Adapter.Gun ` . Another option is to use ` GRPC.Client.Adapters.Mint ` instead, like so:
184+
185+ ``` elixir
186+ GRPC .Stub .connect (" localhost:50051" ,
187+ # Use Mint adapter instead of default Gun
188+ adapter: GRPC .Client .Adapters .Mint
189+ )
190+ ```
191+
192+ The ` GRPC.Client.Adapters.Mint ` adapter accepts custom configuration. To do so, you can configure it from your mix application via:
193+
194+ ``` elixir
195+ # File: your application's config file.
196+ config :grpc , GRPC .Client .Adapters .Mint , custom_opts
197+ ```
97198
98- We will use this module [ in the gRPC server startup section ] ( #start-application ) .
199+ The accepted options for configuration are the ones listed on [ Mint.HTTP.connect/4 ] ( https://hexdocs.pm/mint/Mint.HTTP.html#connect/4-options )
99200
100- ** Note:** For other types of RPC call like streams see [ here] ( interop/lib/interop/server.ex ) .
101201
102202### ** HTTP Transcoding**
103203
@@ -160,10 +260,7 @@ defmodule Helloworld.Greeter.Server do
160260 service: Helloworld .Greeter .Service ,
161261 http_transcode: true
162262
163- @spec say_hello (Helloworld .HelloRequest .t , GRPC .Server .Stream .t ) :: Helloworld .HelloReply .t
164- def say_hello (request, _stream ) do
165- %Helloworld .HelloReply {message: " Hello #{ request.name } " }
166- end
263+ # callback implementations...
167264end
168265```
169266
@@ -186,60 +283,6 @@ defmodule Helloworld.Endpoint do
186283end
187284```
188285
189- ### ** Start Application**
190-
191- 1 . Start gRPC Server in your supervisor tree or Application module:
192-
193- ``` elixir
194- # In the start function of your Application
195- defmodule HelloworldApp do
196- use Application
197- def start (_type , _args ) do
198- children = [
199- # ...
200- {GRPC .Server .Supervisor , endpoint: Helloworld .Endpoint , port: 50051 , start_server: true }
201- ]
202-
203- opts = [strategy: :one_for_one , name: YourApp ]
204- Supervisor .start_link (children, opts)
205- end
206- end
207- ```
208-
209- 2 . Call rpc:
210-
211- ``` elixir
212- iex> {:ok , channel} = GRPC .Stub .connect (" localhost:50051" )
213- iex> request = Helloworld .HelloRequest .new (name: " grpc-elixir" )
214- iex> {:ok , reply} = channel |> Helloworld .Greeter .Stub .say_hello (request)
215-
216- # With interceptors
217- iex> {:ok , channel} = GRPC .Stub .connect (" localhost:50051" , interceptors: [GRPC .Client .Interceptors .Logger ])
218- .. .
219- ```
220-
221- Check the [ examples] ( examples ) and [ interop] ( interop ) directories in the project's source code for some examples.
222-
223- ## Client Adapter and Configuration
224-
225- The default adapter used by ` GRPC.Stub.connect/2 ` is ` GRPC.Client.Adapter.Gun ` . Another option is to use ` GRPC.Client.Adapters.Mint ` instead, like so:
226-
227- ``` elixir
228- GRPC .Stub .connect (" localhost:50051" ,
229- # Use Mint adapter instead of default Gun
230- adapter: GRPC .Client .Adapters .Mint
231- )
232- ```
233-
234- The ` GRPC.Client.Adapters.Mint ` adapter accepts custom configuration. To do so, you can configure it from your mix application via:
235-
236- ``` elixir
237- # File: your application's config file.
238- config :grpc , GRPC .Client .Adapters .Mint , custom_opts
239- ```
240-
241- The accepted options for configuration are the ones listed on [ Mint.HTTP.connect/4] ( https://hexdocs.pm/mint/Mint.HTTP.html#connect/4-options )
242-
243286## Features
244287
245288- Various kinds of RPC:
0 commit comments