### Start gRPC Client Manually Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/README.md Manually start the GRPC.Client.Supervisor in scripts or test environments. ```elixir {:ok, _pid} = DynamicSupervisor.start_link(strategy: :one_for_one, name: GRPC.Client.Supervisor) ``` -------------------------------- ### Protobuf File Definition Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Define your service and messages using protobuf syntax. This example shows a simple greeting service. ```protobuf syntax = "proto3"; package helloworld; // The request message containing the user's name. message HelloRequest { string name = 1; } // The response message containing the greeting message HelloReply { string message = 1; } // The greeting service definition. service GreetingServer { rpc SayUnaryHello (HelloRequest) returns (HelloReply) {} rpc SayServerHello (HelloRequest) returns (stream HelloReply) {} rpc SayBidStreamHello (stream HelloRequest) returns (stream HelloReply) {} } ``` -------------------------------- ### Install gRPC Elixir Client Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/README.md Add the gRPC and optional Protobuf packages to your application's dependencies. ```elixir def deps do [ {:grpc, "~> 0.11"}, {:protobuf, "~> 0.14"} # optional for import wellknown google types ] end ``` -------------------------------- ### Start GRPC Client Supervisor Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/README.md Add the GRPC.Client.Supervisor to your application's supervision tree to manage client connections. Alternatively, start it manually in scripts or test environments. ```elixir children = [ {GRPC.Client.Supervisor, []} ] opts = [strategy: :one_for_one, name: MyApp.Supervisor] Supervisor.start_link(children, opts) ``` ```elixir {:ok, _pid} = DynamicSupervisor.start_link(strategy: :one_for_one, name: GRPC.Client.Supervisor) ``` -------------------------------- ### Start gRPC Client Supervisor Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/README.md Include the GRPC.Client.Supervisor in your application's supervision tree for automatic management. ```elixir children = [ {GRPC.Client.Supervisor, []} ] opts = [strategy: :one_for_one, name: MyApp.Supervisor] Supervisor.start_link(children, opts) ``` -------------------------------- ### Protobuf Definition with HTTP Annotations Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/README.md Define RPC methods in your protobuf file and annotate them with google.api.http for gRPC-gateway transcoding. This example shows GET and POST methods with path parameters and request bodies. ```protobuf import "google/api/annotations.proto"; import "google/protobuf/timestamp.proto"; package helloworld; // The greeting service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) { option (google.api.http) = { get: "/v1/greeter/{name}" }; } rpc SayHelloFrom (HelloRequestFrom) returns (HelloReply) { option (google.api.http) = { post: "/v1/greeter" body: "*" }; } } ``` -------------------------------- ### Start Client Supervisor Manually Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Manually start the gRPC client supervisor, typically used in scripts or test environments. ```elixir DynamicSupervisor.start_link(strategy: :one_for_one, name: GRPC.Client.Supervisor) ``` -------------------------------- ### Define Protobuf Service Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/guides/getting_started/codegen.md Define your message structures and service methods using Protocol Buffers syntax. This example defines a simple Hello service with unary, server-streaming, and bidirectional-streaming RPCs. ```protobuf syntax = "proto3"; package helloworld; // The request message containing the user's name. message HelloRequest { string name = 1; } // The response message containing the greeting message HelloReply { string message = 1; } // The greeting service definition. service GreetingServer { rpc SayUnaryHello (HelloRequest) returns (HelloReply) {} rpc SayServerHello (HelloRequest) returns (stream HelloReply) {} rpc SayBidStreamHello (stream HelloRequest) returns (stream HelloReply) {} } ``` -------------------------------- ### Start Client Supervisor in Application Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Include the gRPC client supervisor in your application's supervision tree for managing client connections. ```elixir children = [ {GRPC.Client.Supervisor, []} ] opts = [strategy: :one_for_one, name: MyApp.Supervisor] Supervisor.start_link(children, opts) ``` -------------------------------- ### Legacy Script: Start Worker Source: https://github.com/elixir-grpc/grpc/blob/master/benchmark/README.md Starts a gRPC worker using legacy scripts. This script is preserved for backward compatibility and requires the --port option. ```bash elixir bin/worker.exs --port=10000 ``` -------------------------------- ### Example Custom JSON Codec Implementation Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/advanced/custom_codecs.md A complete example of a custom JSON codec that prefixes JSON data with 'CUSTOM:'. Ensure the encode and decode functions handle this prefix correctly. ```elixir defmodule MyApp.CustomJSONCodec do @behaviour GRPC.Codec @impl true def name(), do: "custom-json" @impl true def encode(struct, _opts \ []) do json = Protobuf.JSON.encode!(struct) "CUSTOM:" <> json end @impl true def decode(binary, module) do "CUSTOM:" <> json = binary Protobuf.JSON.decode!(json, module) end end ``` -------------------------------- ### Server-Side Streaming RPC Implementation Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Implement server-side streaming RPCs. This example generates a stream of 10 HelloReply messages. ```elixir def say_server_hello(request, materializer) do Stream.repeatedly(fn -> index = :rand.uniform(10) %HelloReply{message: "[#{index}] Hello #{request.name}"} end) |> Stream.take(10) |> GRPC.Stream.from() |> GRPC.Stream.run_with(materializer) end ``` -------------------------------- ### Start gRPC Worker Server Source: https://github.com/elixir-grpc/grpc/blob/master/benchmark/README.md Starts a gRPC worker server on a specified port. The server runs until a quit signal is received. Requires the --port option. ```bash mix benchmark.worker --port=10000 ``` -------------------------------- ### Implement Server-Side Streaming RPC Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/README.md Implement a server-side streaming RPC by generating a stream of replies. This example uses Stream.repeatedly and Stream.take to create a finite stream. ```elixir def say_server_hello(request, materializer) do Stream.repeatedly(fn -> index = :rand.uniform(10) %HelloReply{message: "[#{index}] Hello #{request.name}"} end) |> Stream.take(10) |> GRPC.Stream.from() |> GRPC.Stream.run_with(materializer) end ``` -------------------------------- ### Unary RPC Implementation using Stream API Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Implement unary RPCs using the stream-based API. This example shows how to handle a unary request and map the reply. ```elixir defmodule HelloworldStreams.Server do use GRPC.Server, service: Helloworld.GreetingServer.Service alias GRPC.Stream alias Helloworld.HelloRequest alias Helloworld.HelloReply @spec say_unary_hello(HelloRequest.t(), GRPC.Server.Stream.t()) :: any() def say_unary_hello(request, materializer) do request |> GRPC.Stream.unary(materializer: materializer) |> GRPC.Stream.map(fn %HelloReply{} = reply -> %HelloReply{message: "[Reply] #{reply.message}"} end) |> GRPC.Stream.run() end end ``` -------------------------------- ### Implement Bidirectional Streaming RPC Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/README.md Implement a bidirectional streaming RPC where both the client and server send streams of messages. This example maps incoming requests and joins them with a server-generated output stream. ```elixir @spec say_bid_stream_hello(Enumerable.t(), GRPC.Server.Stream.t()) :: any() def say_bid_stream_hello(request, materializer) do output_stream = Stream.repeatedly(fn -> index = :rand.uniform(10) %HelloReply{message: "[#{index}] Server response"} end) GRPC.Stream.from(request, join_with: output_stream) |> GRPC.Stream.map(fn %HelloRequest{name: name} -> %HelloReply{message: "Welcome #{name}"} other -> other end) |> GRPC.Stream.run_with(materializer) end ``` -------------------------------- ### Define an Unregistered Codec Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/advanced/custom_codecs.md Implement the GRPC.Codec behavior for a custom codec. This example defines a codec named 'unregistered' with basic encode and decode functions. It's used to demonstrate error handling when a client uses an unregistered codec. ```elixir defmodule UnregisteredCodec do @behaviour GRPC.Codec def name(), do: "unregistered" def encode(struct, _opts \ []), do: inspect(struct) def decode(binary, _module), do: binary end ``` -------------------------------- ### Handle Replies and Errors in gRPC Unary Call Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/README.md This example demonstrates a unified error handling model within a gRPC unary call using `GRPCStream.map/2` to transform successful replies and normalize errors. ```elixir def say_unary_hello(request, _materializer) do GRPCStream.unary(request) |> GRPCStream.ask(Transformer) |> GRPCStream.map(fn %HelloReply{} = reply -> %HelloReply{message: "[Reply] #{reply.message}"} {:error, reason} -> {:error, GRPC.RPCError.exception(message: "error calling external process: #{inspect(reason)}")} error -> Logger.error("Unknown error") error end) |> GRPCStream.run() end ``` -------------------------------- ### Unified Error Handling in gRPC Streams Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/guides/getting_started/error_handling.md This example demonstrates how to handle both successful transformations and errors within a single `map/2` operation in a gRPC stream. It shows how to convert errors into `GRPC.RPCError` for consistent propagation. ```elixir def say_unary_hello(request, _materializer) do GRPCStream.unary(request) |> GRPCStream.ask(Transformer) |> GRPCStream.map(fn %HelloReply{} = reply -> %HelloReply{message: "[Reply] #{reply.message}"} {:error, reason} -> {:error, GRPC.RPCError.exception(message: "error calling external process: #{inspect(reason)}")} error -> Logger.error("Unknown error") error end) |> GRPCStream.run() end ``` -------------------------------- ### HTTP Request to gRPC Service Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/advanced/custom_codecs.md Example of making an HTTP POST request to a gRPC service endpoint that has HTTP transcoding enabled. The request body is JSON, and the response will be encoded using GRPC.Codec.JSON, regardless of any custom codecs configured on the server. ```bash curl -X POST http://localhost:50051/myapp.Greeter/SayHello \ -H "Content-Type: application/json" \ -d '{"name": "World"}' ``` -------------------------------- ### Configure Mint Adapter Options Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Set global configuration options for the Mint gRPC client adapter via your application's configuration files. ```elixir # File: config/config.exs config :grpc, GRPC.Client.Adapters.Mint, timeout: 10_000, transport_opts: [cacertfile: "/etc/ssl/certs/ca-certificates.crt"] ``` -------------------------------- ### Client Connections with Different Codecs Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/advanced/custom_codecs.md Demonstrates establishing separate client connections, each configured to use a different codec (Proto, custom JSON, MessagePack). ```elixir # Client 1 uses Proto {:ok, channel1} = GRPC.Stub.connect("localhost:50051", codec: GRPC.Codec.Proto) # Client 2 uses custom JSON {:ok, channel2} = GRPC.Stub.connect("localhost:50051", codec: MyApp.CustomJSONCodec) # Client 3 uses MessagePack {:ok, channel3} = GRPC.Stub.connect("localhost:50051", codec: MyApp.MsgPackCodec) ``` -------------------------------- ### Compile Protobufs with GRPCWithOptions Plugin Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Use the `mix protobuf.generate` task with the `ProtobufGenerate.Plugins.GRPCWithOptions` plugin to generate Elixir code from protobuf files, including HTTP transcoding configurations. ```shell mix protobuf.generate \ --include-path=priv/proto \ --include-path=deps/googleapis \ --generate-descriptors=true \ --output-path=./lib \ --plugins=ProtobufGenerate.Plugins.GRPCWithOptions \ google/api/annotations.proto google/api/http.proto helloworld.proto ``` -------------------------------- ### Add Client Adapter Dependency Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Specify the desired gRPC client adapter (Gun or Mint) in your `mix.exs` file to manage dependencies. ```elixir def deps do [ # Gun {:gun, "~> 2.0"}, # Mint {:mint, "~> 1.5"} ] end ``` -------------------------------- ### Protobuf Generation Command Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/README.md Compile your protobuf files using the 'mix protobuf.generate' command. Specify include paths, output directory, and the desired plugins. This command generates descriptors and uses the GRPCWithOptions plugin. ```shell mix protobuf.generate \ --include-path=priv/proto \ --include-path=deps/googleapis \ --generate-descriptors=true \ --output-path=./lib \ --plugins=ProtobufGenerate.Plugins.GRPCWithOptions \ google/api/annotations.proto google/api/http.proto helloworld.proto ``` -------------------------------- ### Run gRPC Benchmark Tests Source: https://github.com/elixir-grpc/grpc/blob/master/benchmark/README.md Executes gRPC benchmark tests. Defaults to port 10000 and 1000 requests. Customizations for port and number of requests are supported. ```bash mix benchmark.test ``` ```bash mix benchmark.test --port=9999 ``` ```bash mix benchmark.test --requests=5000 ``` ```bash mix benchmark.test --port=9999 --requests=5000 ``` -------------------------------- ### Legacy Script: Run Test Source: https://github.com/elixir-grpc/grpc/blob/master/benchmark/README.md Runs gRPC benchmark tests using legacy scripts. This script is preserved for backward compatibility. ```bash elixir bin/test.exs ``` -------------------------------- ### Configure Mint Adapter Globally Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/getting_started/client.md Configures options for the Mint adapter globally within the application's configuration file. These options are passed to Mint.HTTP.connect/4. ```elixir # File: config/config.exs config :grpc, GRPC.Client.Adapters.Mint, timeout: 10_000, transport_opts: [cacertfile: "/etc/ssl/certs/ca-certificates.crt"] ``` -------------------------------- ### Compile Protobufs with protoc Elixir Plugin Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/guides/getting_started/codegen.md Use the `protoc` compiler with the `--elixir_out` plugin to generate Elixir gRPC code. Specify the output directory and include paths. ```bash protoc --elixir_out=plugins=grpc:./lib -I./priv/protos helloworld.proto ``` -------------------------------- ### Connect using Mint Adapter Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/getting_started/client.md Connects to a gRPC server using the Mint adapter instead of the default Gun adapter. Mint is a pure Elixir HTTP/2 client. ```elixir iex> GRPC.Stub.connect("localhost:50051", ...> adapter: GRPC.Client.Adapters.Mint ...> ) ``` -------------------------------- ### Compile Protobufs with Elixir Plugin Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Use protoc with the elixir plugin to generate gRPC-compatible Elixir modules from your .proto files. ```bash protoc --elixir_out=plugins=grpc:./lib -I./priv/protos helloworld.proto ``` -------------------------------- ### Connect using Mint Adapter Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Explicitly configure the gRPC client to use the Mint adapter for connections. This adapter is a pure Elixir HTTP/2 implementation. ```elixir GRPC.Stub.connect("localhost:50051", adapter: GRPC.Client.Adapters.Mint ) ``` -------------------------------- ### Connect with Compression and Metadata Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/getting_started/client.md Establishes a connection with message compression (Gzip) and default headers for authorization. These settings apply to all requests made through this channel. ```elixir iex> {:ok, channel} = ...> GRPC.Stub.connect("localhost:50051", ...> compressor: GRPC.Compressor.Gzip, ...> headers: [{"authorization", "Bearer my-token"}] ...> ) ``` -------------------------------- ### Add gRPC Server Dependency Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/README.md Add the :grpc_server dependency to your mix.exs file to use the server. The :protobuf and :grpc_reflection packages are optional. ```elixir def deps do [ {:grpc_server, "~> 1.0"}, {:protobuf, "~> 0.14"}, # optional for import wellknown google types {:grpc_reflection, "~> 0.2"} # optional enable grpc reflection ] end ``` -------------------------------- ### Mix Dependencies for Protobuf Generation Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/README.md Add the grpc and protobuf_generate dependencies to your mix.exs file to compile protobuf definitions. Ensure you are using compatible versions. ```elixir def deps do [ {:grpc, "~> 0.11"}, {:protobuf_generate, "~> 0.1.3"} ] end ``` -------------------------------- ### Connect with Compression and Headers Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Configure a gRPC connection to use message compression (e.g., Gzip) and set default request headers, such as authorization tokens. ```elixir iex> {:ok, channel} = ...> GRPC.Stub.connect("localhost:50051", ...> compressor: GRPC.Compressor.Gzip, ...> headers: [{"authorization", "Bearer my-token"}] ...> ) ``` -------------------------------- ### Connect to gRPC Server and Perform Unary RPC Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/getting_started/client.md Establishes a connection to a gRPC server and performs a basic unary RPC call. Ensure the server is running and accessible. ```elixir iex> {:ok, channel} = GRPC.Stub.connect("localhost:50051") iex> request = Helloworld.HelloRequest.new(name: "grpc-elixir") iex> {:ok, reply} = channel |> Helloworld.GreetingServer.Stub.say_unary_hello(request) ``` -------------------------------- ### Compile Protobufs with protobuf_generate Mix Task Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/guides/getting_started/codegen.md Utilize the `mix protobuf.generate` task for more advanced code generation, including options for descriptors and HTTP transcoding. This is useful for integrating with services like Google APIs. ```shell mix protobuf.generate \ --include-path=priv/proto \ --include-path=deps/googleapis \ --generate-descriptors=true \ --output-path=./lib \ --plugins=ProtobufGenerate.Plugins.GRPCWithOptions \ google/api/annotations.proto google/api/http.proto helloworld.proto ``` -------------------------------- ### Connect using Mint Adapter Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/README.md Specify the Mint adapter for gRPC connections, providing a pure Elixir HTTP/2 implementation. This can be configured globally in your application's config. ```elixir iex> GRPC.Stub.connect("localhost:50051", ...> adapter: GRPC.Client.Adapters.Mint ...> ) ``` ```elixir # File: config/config.exs config :grpc, GRPC.Client.Adapters.Mint, timeout: 10_000, transport_opts: [cacertfile: "/etc/ssl/certs/ca-certificates.crt"] ``` -------------------------------- ### Add grpc_core Dependency Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_core/README.md Add `grpc_core` to your project's dependencies in `mix.exs` to include it in your build. ```elixir def deps do [ {:grpc_core, "~> 0.12"} ] end ``` -------------------------------- ### Multiple Codecs Support on Server Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/advanced/custom_codecs.md Servers can support multiple codecs simultaneously by listing them in the `codecs` option. The client's `content-type` header determines which codec is used. ```elixir defmodule MyApp.Greeter.Server do use GRPC.Server, service: MyApp.Greeter.Service, codecs: [ GRPC.Codec.Proto, # application/grpc+proto MyApp.CustomJSONCodec, # application/grpc+custom-json MyApp.MsgPackCodec # application/grpc+msgpack ] def say_hello(request, _stream) do %MyApp.HelloReply{message: "Hello, #{request.name}!"} end end ``` -------------------------------- ### Enable HTTP Transcoding in GRPC Server Module Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Set `http_transcode: true` in your `GRPC.Server` definition to enable HTTP transcoding for the service. This requires the protobuf definitions to include `google.api.http` annotations. ```elixir defmodule Helloworld.Greeter.Server do use GRPC.Server, service: Helloworld.Greeter.Service, http_transcode: true # callback implementations... end ``` -------------------------------- ### Custom Codec - unpack_from_channel/1 Callback Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/advanced/custom_codecs.md The optional unpack_from_channel/1 callback is executed before decoding, useful for transformations like Base64 decoding. ```elixir @impl true def unpack_from_channel(binary) do Base.decode64!(binary) end ``` -------------------------------- ### Run gRPC Interoperability Test Source: https://github.com/elixir-grpc/grpc/blob/master/interop/README.md Execute the Elixir script to run the gRPC interoperability test. The message "Succeed!" is printed upon successful completion. ```bash # "Succeed!" is printed at last when succeed. $ mix run script/run.exs ``` -------------------------------- ### Connect with Interceptors Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Establish a gRPC connection and apply interceptors, such as a logger, to process requests and responses. ```elixir iex> {:ok, channel} = ...> GRPC.Stub.connect("localhost:50051", ...> interceptors: [GRPC.Client.Interceptors.Logger] ...> ) iex> request = Helloworld.HelloRequest.new(name: "Alice") iex> {:ok, reply} = channel |> Helloworld.GreetingServer.Stub.say_unary_hello(request) ``` -------------------------------- ### Configure gRPC Server with TLS Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/README.md Configure TLS for the gRPC server by assigning a `GRPC.Credential{}` struct to the `cred` key within `adapter_opts`. ```elixir { GRPC.Server.Supervisor, [ endpoint: Helloworld.Endpoint, port: 50051, start_server: true, adapter_opts: [cred: GRPC.Credential.new(ssl: Application.get_env(:my_app, :ssl))] ] } ``` -------------------------------- ### Server-Side Configuration - Registering Custom Codecs Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/advanced/custom_codecs.md Register custom codecs when defining your server using the `codecs` option. The first codec in the list is the default. ```elixir defmodule MyApp.Greeter.Server do use GRPC.Server, service: MyApp.Greeter.Service, codecs: [MyApp.CustomJSONCodec, GRPC.Codec.Proto] def say_hello(request, _stream) do %MyApp.HelloReply{message: "Hello, #{request.name}!"} end end ``` -------------------------------- ### Custom Codec - pack_for_channel/1 Callback Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/advanced/custom_codecs.md The optional pack_for_channel/1 callback is executed after encoding, useful for transformations like Base64 encoding before sending. ```elixir @impl true def pack_for_channel(iodata) do Base.encode64(IO.iodata_to_binary(iodata)) end ``` -------------------------------- ### Enable Automatic Reconnection with Mint Adapter Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/README.md Enable automatic reconnection for the Mint adapter by specifying the `:retry` option. This attempts to re-establish the connection up to a configured number of times using exponential backoff. ```elixir iex> {:ok, channel} = GRPC.Stub.connect("localhost:50051", ...> adapter: GRPC.Client.Adapters.Mint, ...> adapter_opts: [retry: 5] ...> ) ``` -------------------------------- ### Add Server Supervisor to Application Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Integrate the gRPC server supervisor into your Elixir application's supervision tree by adding it to the `children` list. ```elixir defmodule Helloworld.Application do @moduledoc false use Application @impl true def start(_type, _args) do children = [ GrpcReflection, { GRPC.Server.Supervisor, [ endpoint: Helloworld.Endpoint, port: 50051, start_server: true, # adapter_opts: [# any adapter-specific options like tls configuration....] ] } ] opts = [strategy: :one_for_one, name: Helloworld.Supervisor] Supervisor.start_link(children, opts) end end ``` -------------------------------- ### Define HTTP Transcoding Annotations in Protobuf Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Add `google.api.http` annotations to your protobuf service definitions to enable HTTP transcoding. This allows gRPC services to be accessed via HTTP requests. ```protobuf import "google/api/annotations.proto"; import "google/protobuf/timestamp.proto"; package helloworld; // The greeting service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) { option (google.api.http) = { get: "/v1/greeter/{name}" }; } rpc SayHelloFrom (HelloRequestFrom) returns (HelloReply) { option (google.api.http) = { post: "/v1/greeter" body: "*" }; } } ``` -------------------------------- ### Implement Custom Codec - GRPC.Codec Behaviour Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/advanced/custom_codecs.md Implement the GRPC.Codec behaviour to create a custom codec. This involves defining the name, encode, and decode functions. ```elixir defmodule MyApp.CustomCodec do @behaviour GRPC.Codec @impl true def name(), do: "custom-format" @impl true def encode(struct, _opts \ []) do # Convert the protobuf struct to your custom format # Return iodata end @impl true def decode(binary, module) do # Convert binary data back to the protobuf struct # Return the decoded struct end end ``` -------------------------------- ### Enable HTTP Transcoding in Server Module Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/README.md Set the http_transcode option to true in your GRPC.Server definition to enable HTTP transcoding. This allows your gRPC service to be accessed via HTTP requests. ```elixir defmodule Helloworld.Greeter.Server do use GRPC.Server, service: Helloworld.Greeter.Service, http_transcode: true # callback implementations... end ``` -------------------------------- ### Custom Codec - name/0 Callback Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/advanced/custom_codecs.md The name/0 callback returns a unique string identifier for your codec, used in the content-type header (e.g., application/grpc+custom-format). ```elixir def name(), do: "custom-format" ``` -------------------------------- ### Custom Codec - decode/2 Callback Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/advanced/custom_codecs.md The decode/2 callback deserializes binary data back into a struct. It takes the binary data and the target struct's module as arguments. ```elixir def decode(binary, module) do # Convert binary data back to the protobuf struct # Return the decoded struct end ``` -------------------------------- ### gRPC Server with HTTP Transcoding and Custom Codecs Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/advanced/custom_codecs.md Define a gRPC server that enables HTTP transcoding and attempts to register a custom codec. Note that the custom codec 'MyApp.CustomJSONCodec' will be ignored for HTTP transcoding, as the library always defaults to GRPC.Codec.JSON in this scenario. ```elixir defmodule MyApp.Greeter.Server do use GRPC.Server, service: MyApp.Greeter.Service, http_transcode: true, codecs: [MyApp.CustomJSONCodec] # Will be ignored for HTTP transcoding def say_hello(request, _stream) do %MyApp.HelloReply{message: "Hello!"} end end ``` -------------------------------- ### Configure gRPC Server Supervisor Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/README.md Add the gRPC server supervisor to your application's supervision tree to manage the gRPC server lifecycle. Specify the endpoint and port for the server. ```elixir defmodule Helloworld.Application do @moduledoc false use Application @impl true def start(_type, _args) do children = [ GrpcReflection, { GRPC.Server.Supervisor, [ endpoint: Helloworld.Endpoint, port: 50051, start_server: true, # adapter_opts: [# any adapter-specific options like tls configuration....] ] } ] opts = [strategy: :one_for_one, name: Helloworld.Supervisor] Supervisor.start_link(children, opts) end end ``` -------------------------------- ### Connect to gRPC Service via Unix Domain Socket Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/advanced/load_balancing.md Use this to establish a connection to a gRPC service using a Unix domain socket. This is useful for local inter-process communication. ```elixir iex> {:ok, channel} = GRPC.Stub.connect("unix:/tmp/my.sock") ``` -------------------------------- ### gRPC Elixir Dependencies Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Add these dependencies to your mix.exs file to use gRPC Elixir. Ensure you use :grpc_server for versions v1.0.0-rc.1 and later. ```elixir def deps do [ {:grpc, "~> 0.11"}, {:grpc_server, "~> 0.11"}, {:protobuf, "~> 0.14"}, # optional for import wellknown google types {:grpc_reflection, "~> 0.2"} # optional enable grpc reflection ] end ``` -------------------------------- ### Custom Codec - encode/2 Callback Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/advanced/custom_codecs.md The encode/2 callback serializes a struct into binary data or iodata. It takes the struct and optional options as arguments. ```elixir def encode(struct, _opts \ []) do # Convert the protobuf struct to your custom format # Return iodata end ``` -------------------------------- ### Bidirectional Streaming with GRPC.Stream Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Implements a bidirectional streaming RPC where the server sends repeated responses and processes client requests. Requires Enumerable and GRPC.Server.Stream. ```elixir @spec say_bid_stream_hello(Enumerable.t(), GRPC.Server.Stream.t()) :: any() def say_bid_stream_hello(request, materializer) do output_stream = Stream.repeatedly(fn -> index = :rand.uniform(10) %HelloReply{message: "[#{index}] Server response"} end) GRPC.Stream.from(request, join_with: output_stream) |> GRPC.Stream.map(fn %HelloRequest{name: name} -> %HelloReply{message: "Welcome #{name}"} other -> other end) |> GRPC.Stream.run_with(materializer) end ``` -------------------------------- ### Connect with a Custom Codec and Test Error Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/advanced/custom_codecs.md Connect to a gRPC channel using a custom codec and attempt a request. This snippet demonstrates how the server responds with an UNIMPLEMENTED status (code 12) if the client's content-type header specifies a codec not registered on the server. ```elixir {:ok, channel} = GRPC.Stub.connect("localhost:50051", codec: UnregisteredCodec) request = %MyApp.HelloRequest{name: "Test"} {:error, %GRPC.RPCError{status: 12}} = MyApp.Greeter.Stub.say_hello(channel, request) # Status 12 = UNIMPLEMENTED ``` -------------------------------- ### Connect with Client Interceptors Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/getting_started/client.md Connects to a gRPC server with client interceptors enabled, such as logging. Interceptors can add logic to the request/response lifecycle. ```elixir iex> {:ok, channel} = ...> GRPC.Stub.connect("localhost:50051", ...> interceptors: [GRPC.Client.Interceptors.Logger] ...> ) iex> request = Helloworld.HelloRequest.new(name: "Alice") iex> {:ok, reply} = channel |> Helloworld.GreetingServer.Stub.say_unary_hello(request) ``` -------------------------------- ### Connect using DNS Scheme Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Connect to a gRPC service using a DNS-based target scheme. The client will resolve the service endpoint via DNS records. ```elixir iex> {:ok, channel} = GRPC.Stub.connect("dns://orders.prod.svc.cluster.local:50051") iex> request = Orders.GetOrderRequest.new(id: "123") iex> {:ok, reply} = channel |> Orders.OrderService.Stub.get_order(request) ``` -------------------------------- ### Connect to gRPC Service via DNS Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/advanced/load_balancing.md Use this to establish a connection to a gRPC service using DNS resolution. The connection layer periodically refreshes endpoints when using DNS targets. ```elixir iex> {:ok, channel} = GRPC.Stub.connect("dns://orders.prod.svc.cluster.local:50051") iex> request = Orders.GetOrderRequest.new(id: "123") iex> {:ok, reply} = channel |> Orders.OrderService.Stub.get_order(request) ``` -------------------------------- ### Implement Unary RPC using Stream API Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/README.md Implement a unary RPC call using the stream-based API. This involves mapping the incoming request and returning a transformed reply. ```elixir defmodule HelloworldStreams.Server do use GRPC.Server, service: Helloworld.GreetingServer.Service alias GRPC.Stream alias Helloworld.HelloRequest alias Helloworld.HelloReply @spec say_unary_hello(HelloRequest.t(), GRPC.Server.Stream.t()) :: any() def say_unary_hello(request, materializer) do request |> GRPC.Stream.unary(materializer: materializer) |> GRPC.Stream.map(fn %HelloRequest{} = reply -> %HelloReply{message: "[Reply] #{reply.message}"} end) |> GRPC.Stream.run() end end ``` -------------------------------- ### Client-Side Usage - Set Default Codec on Connection Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/advanced/custom_codecs.md Set the default codec for a gRPC connection using the `codec` option during `GRPC.Stub.connect`. This codec will be used for all requests on that channel unless overridden. ```elixir {:ok, channel} = GRPC.Stub.connect("localhost:50051", codec: MyApp.CustomJSONCodec) request = %MyApp.HelloRequest{name: "World"} {:ok, reply} = MyApp.Greeter.Stub.say_hello(channel, request) ``` -------------------------------- ### Transforming Errors in a Stream Pipeline Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Demonstrates using `map_error/2` to catch and transform exceptions raised within a stream's `map/2` operator into a structured GRPC.RPCError. ```elixir iex> GRPC.Stream.from([1, 2]) ...> |> GRPC.Stream.map(fn ...> 2 -> raise "boom" ...> x -> x ...> end) ...> |> GRPC.Stream.map_error(fn ...> {:error, {:exception, _reason}} -> ...> {:error, GRPC.RPCError.exception(message: "Booomm")} ...> end) ``` -------------------------------- ### Client-Side Usage - Override Codec Per Request Source: https://github.com/elixir-grpc/grpc/blob/master/grpc/guides/advanced/custom_codecs.md Override the default codec for a specific request by providing the `codec` option in the stub call. This allows for per-request codec selection. ```elixir {:ok, channel} = GRPC.Stub.connect("localhost:50051") request = %MyApp.HelloRequest{name: "World"} {:ok, reply} = MyApp.Greeter.Stub.say_hello(channel, request, codec: MyApp.CustomJSONCodec) ``` -------------------------------- ### Enable Automatic Reconnection in GRPC Client Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Pass the `:retry` option to `GRPC.Stub.connect` to enable automatic reconnection. The adapter will attempt to reconnect with exponential backoff. If all attempts are exhausted, a `{:elixir_grpc, :connection_down, pid}` message is sent to the parent process. ```elixir iex> {:ok, channel} = GRPC.Stub.connect("localhost:50051", ...> adapter: GRPC.Client.Adapters.Mint, ...> adapter_opts: [retry: 5] ...> ) ``` -------------------------------- ### Execute Side Effects in gRPC Stream Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/README.md Use `effect/2` to perform non-transformative actions like logging for each stream element without altering the stream. Execution is lazy and exceptions are handled internally. ```elixir iex> parent = self() iex> stream = ...> GRPC.Stream.from([1, 2, 3]) ...> |> GRPC.Stream.effect(fn x -> send(parent, {:seen, x * 2}) end) ...> |> GRPC.Stream.to_flow() ...> |> Enum.to_list() iex> assert_receive {:seen, 2} iex> assert_receive {:seen, 4} iex> assert_receive {:seen, 6} iex> stream [1, 2, 3] ``` -------------------------------- ### Configure CORS Interceptor in GRPC Endpoint Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/README.md Add the GRPC.Server.Interceptors.CORS interceptor to your GRPC.Endpoint module to handle Cross-Origin Resource Sharing. Configure allowed origins as needed. ```elixir # Define your endpoint defmodule Helloworld.Endpoint do use GRPC.Endpoint intercept GRPC.Server.Interceptors.Logger intercept GRPC.Server.Interceptors.CORS, allow_origin: "mydomain.io" run Helloworld.Greeter.Server end ``` -------------------------------- ### Configure CORS Interceptor in Elixir gRPC Endpoint Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/guides/advanced/cors.md Add GRPC.Server.Interceptors.CORS as an interceptor to your GRPC.Endpoint module. Configure the allowed origin using the `allow_origin` option. ```elixir defmodule Helloworld.Endpoint do use GRPC.Endpoint intercept GRPC.Server.Interceptors.Logger intercept GRPC.Server.Interceptors.CORS, allow_origin: "mydomain.io" run Helloworld.Greeter.Server end ``` -------------------------------- ### Recovering from Exceptions with map_error/2 Source: https://github.com/elixir-grpc/grpc/blob/master/grpc_server/guides/getting_started/error_handling.md Use `map_error/2` to intercept and transform exceptions or errors within a stream pipeline into structured `GRPC.RPCError` responses. This allows the stream to continue processing without interruption. ```elixir iex> GRPC.Stream.from([1, 2]) ...> |> GRPC.Stream.map(fn ...> 2 -> raise "boom" ...> x -> x ...> end) ...> |> GRPC.Stream.map_error(fn ...> {:error, {:exception, _reason}} -> ...> {:error, GRPC.RPCError.exception(message: "Booomm")} ...> end) ``` -------------------------------- ### Executing Side Effects in a Stream Source: https://github.com/elixir-grpc/grpc/blob/master/README.md Uses the `effect/2` operator to perform actions like logging or metrics for each stream element without altering the stream. The stream is materialized using `Enum.to_list/1`. ```elixir iex> parent = self() iex> stream = ...> GRPC.Stream.from([1, 2, 3]) ...> |> GRPC.Stream.effect(fn x -> send(parent, {:seen, x * 2}) end) ...> |> GRPC.Stream.to_flow() ...> |> Enum.to_list() iex> assert_receive {:seen, 2} iex> assert_receive {:seen, 4} iex> assert_receive {:seen, 6} iex> stream [1, 2, 3] ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.