apigenie-generatorProtobuf and gRPCserver elixir-grpc

server elixir-grpc

Generate an Elixir gRPC server on elixir-grpc from a .proto file and the files it imports.

Usage

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
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:

config :carpet_express, CarpetExpress.ShipmentService, impl: MyApp.ShipmentService
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

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