# server elixir-grpc

Source: https://apigenie.pl/techdocs/reference/cli-generate_server_elixir_grpc

Generate an Elixir gRPC server on [elixir-grpc](https://hexdocs.pm/grpc_server) from a `.proto`
file and the files it imports.

## Usage

```sh
apigenie-generator server elixir-grpc [...OPTIONS] INPUT_FILE
```

## Description

The input is the `.proto` file declaring the services. The files it imports are looked up in the
directories of `--proto-path`, then next to it; `google/protobuf`, `google/api` and `google/rpc`
imports need no files. Only proto3 files are read.

The generator writes a Mix project (Elixir 1.18 or later) depending on `grpc_server` 1.0 and
`protobuf` 0.17. Its code passes `mix format --check-formatted`, `mix compile
--warnings-as-errors`, `mix credo --strict` and `mix dialyzer`. No protoc is needed: the modules of
the messages are those protoc-gen-elixir would write.

| File | Contents |
| ---- | -------- |
| `lib/proto/<path>.pb.ex` | per `.proto` file, a module per message, map entry and enum (`use Protobuf`), and a `<Service>.Service` module per service (`use GRPC.Service`) |
| `lib/<app>/<service>.ex` | a behaviour per service, with a callback per method |
| `lib/<app>/<service>/server.ex` | the `GRPC.Server` of the service, calling the configured implementation |
| `lib/<app>/endpoint.ex`, `application.ex` | the endpoint running the servers, and the application starting it |
| `config/config.exs`, `config/runtime.exs` | the port (50051, or `PORT`) |
| `mix.exs`, `.formatter.exs`, `.gitignore`, `README.md` | the project |

```sh
mix deps.get
mix run --no-halt
```

### Messages

Modules are named as protoc-gen-elixir names them: the package camelized segment by segment, then
the message (`carpetexpress.v1.Shipment.Parcel` is `Carpetexpress.V1.Shipment.Parcel`). The
`(elixirpb.file).module_prefix` option of a file, or the `package_prefix` option of the generator,
change the prefix. Fields are declared with `field` and the options protoc-gen-elixir writes
(`repeated`, `proto3_optional`, `json_name`, `map`, `enum`, `oneof`, `packed`, `deprecated`), oneofs
with `oneof`. Comments become `@moduledoc` and `#` comments.

Well-known types are the modules of the `protobuf` package (`Google.Protobuf.Timestamp`, ...), the
types of `google/api`, `google/rpc` and `google/type` those of `googleapis`.

### Services

A service is a behaviour, `<Root>.<Service>`, with a callback per method named as GRPC.Server names
it (`GetShipment` is `get_shipment/2`). Implement it and configure the implementation:

```elixir
config :carpet_express, CarpetExpress.ShipmentService, impl: MyApp.ShipmentService
```

```elixir
defmodule MyApp.ShipmentService do
  @behaviour CarpetExpress.ShipmentService

  @impl true
  def get_shipment(request, _stream), do: MyApp.Shipments.fetch!(request.id)

  @impl true
  def import_shipments(requests, _stream) do
    imported = requests |> Enum.map(&MyApp.Shipments.book/1) |> length()
    %Carpetexpress.V1.ImportShipmentsResponse{imported: imported}
  end

  # ...
end
```

A callback receives the request, or an `Enumerable` of the requests of a client or bidirectional
stream, and the `GRPC.Server.Stream` of the call. It returns the response, or an `Enumerable` of
the responses of a server or bidirectional stream, which the server sends one by one. Raising
`GRPC.RPCError` answers with its status. Methods without an implementation answer UNIMPLEMENTED.

### Limitations

- `extend` blocks (custom options, proto2-style extensions) aren't generated; a warning names the
  file.
- `(google.api.field_behavior) = REQUIRED` isn't checked: protobuf-elixir has no required fields.
- HTTP/JSON transcoding (`google.api.http`) isn't turned on.

## Options

### -I, --proto-path DIR

Directory searched for the imported files, like protoc's `--proto_path`. Can be repeated.

### -c, --config

Path to the configuration file to use. See the "Configuration" section for more information.

### -o, --output

Directory where the project is generated.

### --package-name

Name of the Mix application, converted to snake_case (`carpet-express` gives `carpet_express`
and the root module `CarpetExpress`). Defaults to the name of the output directory.

### --package-version

Version of the Mix project; `0.1.0` by default.

### -p, --property NAME=VALUE

Sets a generator option (see below), e.g. `-p dev_deps=false`. Options given on the command line
take precedence over the configuration file.

## Configuration

```yaml
version: '1.0'
commands:
  generate:
    server_elixir_grpc:
      app: carpet_express
      package_prefix: carpet_express.proto
```

| Option | Type | Default | Description |
| ------ | ---- | ------- | ----------- |
| `app` | string | name of the output directory | Name of the Mix application (snake_case, the directory under `lib/`); also set by `--package-name`. |
| `namespace` | string | the application in PascalCase | Root module of the modules of the application (behaviours, servers, endpoint), e.g. `CarpetExpress`. |
| `package_prefix` | string | | Prepended to the package in the names of the modules of messages, enums and services, like protoc-gen-elixir's `package_prefix`. |
| `dev_deps` | boolean | `true` | Lists credo and dialyxir as dependencies of `mix.exs` (`only: :dev`). |
