protobuf-elixir

repository·main·Indexed 21 days ago

https://github.com/elixir-protobuf/protobuf

A pure Elixir implementation of Google Protocol Buffers. It provides a protoc plugin to generate Elixir code using structs and macros, supporting typespecs, custom transformations, and gRPC. The library includes utilities for encoding and decoding messages, handling well-known Google Protobuf modules (such as Timestamp, Duration, and Struct), and a conformance test suite to verify adherence to the official Protobuf specification.

Tokens
7.6K
Snippets
34
Records
42
Agent score
74%

What's inside protobuf-elixir

  1. Manage conformance test exemptions

    main

    The file conformance/exemptions.txt maintains a list of tests that are currently known to fail conformance.

    Workflow for fixing issues: When you resolve a conformance issue identified by the test runner, you must remove the corresponding test lines from conformance/exemptions.txt. This ensures that the fix is permanent and that future changes do not introduce regressions.

  2. Generate Elixir code from .proto files

    main

    To generate Elixir modules from your protobuf definitions, follow these steps:

    1. Install protoc: Download and install the Google Protocol Buffer compiler. On macOS, use brew install protobuf.

    2. Install the Elixir plugin: Install the protoc-gen-elixir escript. Ensure the binary is in your PATH (e.g., by adding ~/.mix/escripts to your profile or running asdf reshim).

      Warning: Ensure the version of the escript matches the version of the :protobuf dependency in your application.

      mix escript.install hex protobuf 0.16.0
    3. Run protoc: Use the --elixir_out flag to generate code.

      protoc --elixir_out=./lib helloworld.proto

    This will generate .pb.ex files containing Elixir modules that use the Protobuf module to define fields and types.

    mix escript.install hex protobuf 0.16.0
    protoc --elixir_out=./lib helloworld.proto
  3. Run Protobuf conformance tests

    main

    To verify that the library adheres to the official Protobuf specification, you can run the conformance test suite. This requires a pre-compiled Protobuf conformance test runner binary.

    1. Prerequisite: Compile the Protobuf conformance test runner binary following the instructions in the official Protobuf repository.
    2. Execution: Run the tests using mix conformance_test and provide the path to your compiled runner using the --runner flag.
    mix conformance_test --runner=$PATH_TO_RUNNER
  4. Use custom options with elixirpb.proto

    main

    To use custom options like module_prefix, you must use the elixirpb.proto definition:

    1. Copy src/elixirpb.proto from the :protobuf package to your project's proto directory.
    2. Import elixirpb.proto in your .proto file.
    3. Apply the option using the elixirpb.file extension.
    syntax = "proto2";
    
    package your.pkg;
    
    import "elixirpb.proto";
    
    option (elixirpb.file).module_prefix = "Foo.Bar";
  5. Install protobuf-elixir

    main

    Add :protobuf to your mix.exs dependencies to use the library in your Elixir project.

    Note on Google Protos: Since version 0.14.0, well-known Google Protobuf modules are included by default. If you are using the deprecated :google_protos package, remove it from your dependencies and run mix deps.unlock --unused to avoid conflicts.

    def deps do
      [
        {:protobuf, "~> 0.16.0"}
      ]
    end
  6. Use Google.Protobuf.Value for dynamic typing

    main

    The Google.Protobuf.Value module represents a dynamically typed value. It uses a oneof field named kind to allow a single value to be one of several types. When constructing a Value, you must set exactly one of the following fields:

    • null_value: Uses Google.Protobuf.NullValue (specifically NULL_VALUE) to represent a JSON null.
    • number_value: A :double.
    • string_value: A :string.
    • bool_value: A :boolean.
    • struct_value: A Google.Protobuf.Struct (representing a JSON object).
    • list_value: A Google.Protobuf.ListValue (representing a JSON array).
  7. Represent JSON objects with Google.Protobuf.Struct

    main

    The Google.Protobuf.Struct module represents a structured data value consisting of fields that map to dynamically typed Google.Protobuf.Value instances. It is the Protobuf equivalent of a JSON object.

    It contains a single field:

    • fields: A map (represented as a repeated Google.Protobuf.Struct.FieldsEntry) where keys are strings and values are Google.Protobuf.Value types.
  8. How to use Protobuf extensions

    main

    Protobuf extensions allow you to add extra fields to previously defined messages (even those in other packages) without modifying the original message definition.

    To use extensions in your application, you must first call Protobuf.load_extensions/0 during your application startup (e.g., in your application's start/2 callback) to ensure the extension registry is initialized.

    When working with extensions, you interact with the base message using put_extension/4 and get_extension/4. These functions require the module that defines the extension (the extension module) and the specific field name being extended.

    defmodule MyApp do
      use Application
    
      def start(_type, _args) do
        Protobuf.load_extensions()
        Supervisor.start_link(children(), strategy: :one_for_one)
      end
    end
  9. Implement the Protobuf.Any.TypeProvider behaviour

    main

    To use Protobuf.Any.unpack/2, you must create a module that implements the Protobuf.Any.TypeProvider behaviour. This module acts as a registry to map type_url strings to your generated Elixir message modules.

    Your implementation must include a to_module/1 function with the following signature:

    def to_module(type_url) :: {:ok, module()} | {:error, reason :: any()}

    • Success: Return {:ok, YourModule} where YourModule is the atom of the Elixir module.
    • Failure: Return {:error, reason} if the type_url is not recognized.