Code Monkey home page Code Monkey logo

protobuf's Introduction

protobuf-elixir

CI

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.8.0"},
    # Only for files generated from Google's protos.
    # Can be ignored if you don't use Google's protos.
    # Or you can generate the code by yourself.
    {:google_protos, "~> 0.1"}
  ]
end

Features

  • Define messages with DSL
  • Decode basic messages
  • Skip unknown fields
  • Decode embedded messages
  • Decode packed and repeated fields
  • Encode messages
  • protoc plugin
  • map
  • Support default values
  • Validate values
  • Generate typespecs
  • oneof
  • (proto2) Extension (Experiment, see Protobuf.Extension)

Usage

Generate Elixir code

  1. Download and install the protocol buffer compiler (protoc). MacOS users can also install it through Homebrew with brew install protobuf.

  2. Install protoc plugin protoc-gen-elixir for Elixir using the command below. Make sure the protoc-gen-elixir binary is in your PATH. Either add PATH=~/.mix/escripts:$PATH to your bash or zsh profile or, if you used asdf to install elixir, run asdf reshim and then verify that protoc-gen-elixir works:

    $ mix escript.install hex protobuf
  3. Generate Elixir code using protoc:

    $ protoc --elixir_out=./lib helloworld.proto
  4. A lib/helloworld.pb.ex file 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
    end
    
    defmodule Helloworld.HelloReply do
      use Protobuf, syntax: :proto3
    
      @type t :: %__MODULE__{
        message: String.t()
      }
    
      defstruct [:message]
    
      field :message, 1, type: :string
    end

Encode and decode in your code

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

Note:

  • Use YourModule.new(field: "value") to ensure default values are set correctly for all fields instead of using the struct directly, as in %YourModule{field: "value"}.
  • Validation is done during encoding. An error will be raised if the struct is invalid: when it misses a required field or has a mistyped value.

Descriptor support

If you use any custom options in your protobufs then to gain access to them you'll need to include the raw descriptors in the generated modules. You can generate the descriptors by passing gen_descriptors=true in --elixir_out.

The descriptors will be available on each module from the descriptor/0 function.

$ protoc --elixir_out=gen_descriptors=true:./lib/ *.proto
$ protoc --elixir_out=gen_descriptors=true,plugins=grpc:./lib/ *.proto

Package prefix

You can use the package_prefix option to prefix generated Elixir code.

For example to prefix generated Elixir modules with MyApp.Protos use my_app.protos as package prefix:

$ protoc --elixir_out=./lib --elixir_opt=package_prefix=my_app.protos *.proto

Transformer module

By defining a callback transform_module/0 function on your protobuf message module you can add custom encoding and decoding logic for your message. See the documentation for Protobuf.TransformModule for more details.

If your protobufs are generated from a .proto files you can add the callback function by passing transform_module=... in --elixir_out.

$ protoc --elixir_out=transform_module=MyTransformModule:./lib/ *.proto

One file per module

You can use the one_file_per_module=true option to change the way that files are generated into directories. By default, one .pb.ex file is generated for each .proto file you compile and each of those .pb.ex files can have multiple Elixir module definitions in it.

With one_file_per_module=true, one .pb.ex file will be generated for each generated Elixir module and the directory structure will respect Elixir conventions. For example, a MyPackage.MyMessage message will end up in the my_package/my_message.pb.ex file.

$ protoc --elixir_out=one_file_per_module=true:./lib *.proto

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

Custom options

Since extensions(Protobuf.Extension) is supported now, some options are defined, like custom module_prefix.

  1. Copy src/elixirpb.proto to your protos path.

  2. Import elixirpb.proto and use the options.

    syntax = "proto2";
    
    package your.pkg;
    
    import "elixirpb.proto";
    
    option (elixirpb.file).module_prefix = "Foo.Bar";
  3. Generate code as before.

More options will be added in the future, see elixirpb.proto comments for details.

Tests

mix test

Sponsors

Acknowledgements

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

protobuf's People

Contributors

tony612 avatar whatyouhide avatar britto avatar ericmj avatar zolakeith avatar wingyplus avatar amatalai avatar jeanparpaillon avatar kianmeng avatar haljin avatar hassox avatar connorjacobsen avatar xinz avatar redink avatar falood avatar wojtekmach avatar zentetsukenz avatar ulissesalmeida avatar princemaple avatar mikebveil avatar ktec avatar mrjoelkemp avatar jayh5 avatar jackmarchant avatar qinix avatar ch4s3 avatar cjab avatar bblaszkow06 avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.