Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 18 additions & 100 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,6 @@
- [Bidirectional Streaming](#bidirectional-streaming)
- [Application Startup](#application-startup)
- [Client Usage](#client-usage)
- [Basic Connection and RPC](#basic-connection-and-rpc)
- [Using Interceptors](#using-interceptors)
- [Target Schemes and Resolvers](#target-schemes-and-resolvers)
- [Supported formats](#supported-formats)
- [Example (DNS)](#example-dns)
- [Example (Unix socket)](#example-unix-socket)
- [Compression and Metadata](#compression-and-metadata)
- [Client Adapters](#client-adapters)
- [Using Mint Adapter](#using-mint-adapter)
- [HTTP Transcoding](#http-transcoding)
- [CORS](#cors)
- [Features](#features)
Expand Down Expand Up @@ -87,8 +78,6 @@ protoc --elixir_out=plugins=grpc:./lib -I./priv/protos helloworld.proto

All RPC calls must be implemented using the stream-based API, even for unary requests.

>__NOTE__: The old API was deprecated based on `GRPC.Server.send_reply/2` and direct `struct` returns was deprecated as of version `0.10.x`.

### Unary RPC using Stream API

```elixir
Expand Down Expand Up @@ -144,10 +133,7 @@ def say_bid_stream_hello(request, materializer) do
|> GRPC.Stream.run_with(materializer)
end
```

The Stream API supports composable stream transformations via `ask`, `map`, `run` and other functions, enabling clean and declarative stream pipelines. For a complete list of available operators and detailed documentation, see [`GRPC.Stream`](lib/grpc/stream.ex).

---
__💡__ 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.ex).

## Application Startup

Expand Down Expand Up @@ -180,106 +166,38 @@ end

# Client Usage

This section demonstrates how to establish client connections and perform RPC calls using the Elixir gRPC client.

---

## Basic Connection and RPC

```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)
```

---

## Using Interceptors

Client interceptors allow you to add logic to the request/response lifecycle, such as logging, tracing, or authentication.

```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)
```

---

## Target Schemes and Resolvers

The `connect/2` function supports URI-like targets that are resolved via the internal **gRPC** [Resolver](lib/grpc/client/resolver.ex).
You can connect using `DNS`, `Unix Domain sockets`, `IPv4/IPv6`, or even `xDS-based endpoints`.

### Supported formats:

| Scheme | Example | Description |
|:----------|:----------------------------|:---------------------------------------------|
| `dns://` | `"dns://example.com:50051"` | Resolves via DNS `A/AAAA` records |
| `ipv4:` | `"ipv4:10.0.0.5:50051"` | Connects directly to an IPv4 address |
| `unix:` | `"unix:/tmp/service.sock"` | Connects via a Unix domain socket |
| `xds:///` | `"xds:///my-service"` | Resolves via xDS control plane (Envoy/Istio) |
| none | `"127.0.0.1:50051"` | Implicit DNS (default port `50051`) |

### Example (DNS):

```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)
```

### Example (Unix socket):

```elixir
iex> {:ok, channel} = GRPC.Stub.connect("unix:/tmp/my.sock")
```

>__NOTE__: When using `DNS` or `xDS` targets, the connection layer periodically refreshes endpoints.
---

## Compression and Metadata

You can specify message compression and attach default headers to all requests.

```elixir
iex> {:ok, channel} =
...> GRPC.Stub.connect("localhost:50051",
...> compressor: GRPC.Compressor.Gzip,
...> headers: [{"authorization", "Bearer my-token"}]
...> )
# With interceptors
iex> {:ok, channel} = GRPC.Stub.connect("localhost:50051", interceptors: [GRPC.Client.Interceptors.Logger])
...
```

---

## Client Adapters
Check the [examples](examples) and [interop](interop) directories in the project's source code for some examples.

By default, `GRPC.Stub.connect/2` uses the **Gun** adapter.
You can switch to **Mint** (pure Elixir HTTP/2) or other adapters as needed.
## Client Adapter and Configuration

### Using Mint Adapter
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:

```elixir
iex> GRPC.Stub.connect("localhost:50051",
...> adapter: GRPC.Client.Adapters.Mint
...> )
GRPC.Stub.connect("localhost:50051",
# Use Mint adapter instead of default Gun
adapter: GRPC.Client.Adapters.Mint
)
```

You can configure adapter options globally via your application’s config:
The `GRPC.Client.Adapters.Mint` adapter accepts custom configuration. To do so, you can configure it from your mix application via:

```elixir
# File: config/config.exs
config :grpc, GRPC.Client.Adapters.Mint,
timeout: 10_000,
transport_opts: [cacertfile: "/etc/ssl/certs/ca-certificates.crt"]
# File: your application's config file.
config :grpc, GRPC.Client.Adapters.Mint, custom_opts
```

The accepted options are the same as [`Mint.HTTP.connect/4`](https://hexdocs.pm/mint/Mint.HTTP.html#connect/4-options).
The accepted options for configuration are the ones listed on [Mint.HTTP.connect/4](https://hexdocs.pm/mint/Mint.HTTP.html#connect/4-options)

---

### **HTTP Transcoding**

Expand Down Expand Up @@ -346,7 +264,7 @@ defmodule Helloworld.Greeter.Server do
end
```

See full application code in [helloworld_transcoding](https://github.com/elixir-grpc/tree/master/examples/helloworld_transcoding) example.
See full application code in [helloworld_transcoding](examples/helloworld_transcoding) example.

### **CORS**

Expand Down Expand Up @@ -382,9 +300,9 @@ end

## Benchmark

1. [Simple benchmark](https://github.com/elixir-grpc/tree/master/examples/helloworld/README.md#Benchmark) by using [ghz](https://ghz.sh/)
1. [Simple benchmark](examples/helloworld/README.md#Benchmark) by using [ghz](https://ghz.sh/)

2. [Benchmark](https://github.com/elixir-grpc/tree/master/benchmark) followed by official spec
2. [Benchmark](benchmark) followed by official spec

## Contributing

Expand Down
8 changes: 4 additions & 4 deletions benchmark/lib/grpc/core/stats.pb.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule Grpc.Core.Bucket do
@moduledoc false

use Protobuf, protoc_gen_elixir_version: "0.14.0", syntax: :proto3
use Protobuf, protoc_gen_elixir_version: "0.14.1", syntax: :proto3

field :start, 1, type: :double
field :count, 2, type: :uint64
Expand All @@ -10,15 +10,15 @@ end
defmodule Grpc.Core.Histogram do
@moduledoc false

use Protobuf, protoc_gen_elixir_version: "0.14.0", syntax: :proto3
use Protobuf, protoc_gen_elixir_version: "0.14.1", syntax: :proto3

field :buckets, 1, repeated: true, type: Grpc.Core.Bucket
end

defmodule Grpc.Core.Metric do
@moduledoc false

use Protobuf, protoc_gen_elixir_version: "0.14.0", syntax: :proto3
use Protobuf, protoc_gen_elixir_version: "0.14.1", syntax: :proto3

oneof :value, 0

Expand All @@ -30,7 +30,7 @@ end
defmodule Grpc.Core.Stats do
@moduledoc false

use Protobuf, protoc_gen_elixir_version: "0.14.0", syntax: :proto3
use Protobuf, protoc_gen_elixir_version: "0.14.1", syntax: :proto3

field :metrics, 1, repeated: true, type: Grpc.Core.Metric
end
20 changes: 0 additions & 20 deletions benchmark/lib/grpc/testing/benchmark_service.pb.ex
Original file line number Diff line number Diff line change
@@ -1,21 +1 @@
defmodule Grpc.Testing.BenchmarkService.Service do
@moduledoc false

use GRPC.Service, name: "grpc.testing.BenchmarkService", protoc_gen_elixir_version: "0.14.0"

rpc :UnaryCall, Grpc.Testing.SimpleRequest, Grpc.Testing.SimpleResponse

rpc :StreamingCall, stream(Grpc.Testing.SimpleRequest), stream(Grpc.Testing.SimpleResponse)

rpc :StreamingFromClient, stream(Grpc.Testing.SimpleRequest), Grpc.Testing.SimpleResponse

rpc :StreamingFromServer, Grpc.Testing.SimpleRequest, stream(Grpc.Testing.SimpleResponse)

rpc :StreamingBothWays, stream(Grpc.Testing.SimpleRequest), stream(Grpc.Testing.SimpleResponse)
end

defmodule Grpc.Testing.BenchmarkService.Stub do
@moduledoc false

use GRPC.Stub, service: Grpc.Testing.BenchmarkService.Service
end
Loading
Loading