# protobuf-elixir

[![Build Status](](

A pure Elixir implementation of [Google Protobuf](

## Why this instead of exprotobuf(gpb)?

It has some must-have and other cool features like:

1. A protoc [plugin]( to generate Elixir code just like what other official libs do, which is powerful and reliable.
2. Generate **simple and explicit** code with the power of Macro. (see [test/support/test_msg.ex](
3. Plugins support. Only [grpc]( is supported now.
4. Use **structs** for messages instead of Erlang records.
5. Support Typespec in generated code.

## Installation

The package can be installed by adding `protobuf` to your list of dependencies in `mix.exs`:

def deps do
    {:protobuf, "~> 0.5.3"},
    # Only for files generated from Google's protos.
    # Can be ignored if you don't use Google's protos.
    {:google_protos, "~> 0.1"}

## Features

* [x] Define messages with DSL
* [x] Decode basic messages
* [x] Skip unknown fields
* [x] Decode embedded messages
* [x] Decode packed and repeated fields
* [x] Encode messages
* [x] protoc plugin
* [x] map
* [x] Support default values
* [x] Validate values
* [x] Generate typespecs
* [x] oneof

## Usage

### Generate Elixir code

1. Install `protoc`(cpp) [here]( or `brew install protobuf` on MacOS.
2. Install protoc plugin `protoc-gen-elixir` for Elixir . NOTE: You have to make sure `protoc-gen-elixir`(this name is important) is in your PATH.
$ mix escript.install hex protobuf
3. Generate Elixir code using protoc
$ protoc --elixir_out=./lib helloworld.proto
4. Files `helloworld.pb.ex` will be generated, like:

defmodule Helloworld.HelloRequest do
  use Protobuf, syntax: :proto3

  @type t :: %__MODULE__{
    name: String.t
  defstruct [:name]

  field :name, 1, type: :string

defmodule Helloworld.HelloReply do
  use Protobuf, syntax: :proto3

  @type t :: %__MODULE__{
    message: String.t
  defstruct [:message]

  field :message, 1, type: :string

### Encode and decode in your code

struct = 3.2, c:
encoded = Foo.encode(struct)
struct = Foo.decode(encoded)

- You should use `` instead of using the struct directly because default values will be set for all fields.
- Default values will be set by default in `decode`, which can be changed by `:use_default` option.
- Validation is done in `encode`. An error will be raised if the struct is invalid(like type is not matched).

### gRPC Support

If you write [services]( in protobuf, you can generate [gRPC]( code by passing `plugins=grpc` in `--elixir_out`:
$ protoc --elixir_out=plugins=grpc:./lib/ *.proto

### Tips for protoc

- Custom protoc-gen-elixir name or path using `--plugin`
$ protoc --elixir_out=./lib --plugin=./protoc-gen-elixir *.proto
- Pass `-I` argument if you import other protobuf files
$ protoc -I protos --elixir_out=./lib protos/hello.proto

## Sponsors

This project is being sponsored by [Tubi]( Thank you!

<img src="" height="80">

## Acknowledgements

Many thanks to [gpb]( and
[golang/protobuf]( as good examples of
writing Protobuf decoder/encoder.