Protox (Protox v1.6.3) View Source

Use this module to generate the Elixir structs corresponding to a set of protobuf definitions and to encode/decode instances of these structures.

Elixit structs generation examples

From a set of files:

defmodule Dummy do
  use Protox,
    files: [
      "./defs/foo.proto",
      "./defs/bar.proto",
      "./defs/baz/fiz.proto",
    ]
end

From a string:

defmodule Dummy do
  use Protox,
    schema: """
    syntax = "proto3";
    package fiz;

    message Baz {
    }

    message Foo {
      map<int32, Baz> b = 2;
    }
    """
end

The generated modules respect the package declaration. For instance, in the above example, both the Fiz.Baz and Fiz.Foo modules will be generated.

Encoding/decoding

For the rest of this module documentation, we suppose the following protobuf messages are defined:

defmodule Dummy do
  use Protox,
    schema: """
      syntax = "proto3";
      package fiz;

      message Baz {
      }

      enum Enum {
        FOO = 0;
        BAR = 1;
      }

      message Foo {
        Enum a = 1;
        map<int32, Baz> b = 2;
      }
    """,
    namespace: Namespace

  use Protox,
    schema: """
    syntax = "proto3";

    message Msg {
      map<int32, string> msg_k = 8;
    }
    """

  use Protox,
    schema: """
    syntax = "proto3";

    message Sub {
      int32 a = 1;
    }
    """
end

See each function documentation to see how they are used to encode and decode protobuf messages.

Link to this section Summary

Functions

Decode a binary into a protobuf message.

Throwing version of decode/2.

Encode a protobuf message into IO data.

Throwing version of encode/1.

Errors

This function returns a tuple {:error, reason} if

Export a proto3 message to JSON as IO data.

Link to this section Functions

Link to this function

decode(binary, msg_module)

View Source (since 1.6.0)

Specs

decode(binary(), atom()) :: {:ok, struct()} | {:error, any()}

Decode a binary into a protobuf message.

Examples

iex> binary = <<66, 7, 8, 1, 18, 3, 102, 111, 111, 66, 7, 8, 2, 18, 3, 98, 97, 114>>
iex> {:ok, msg} = Protox.decode(binary, Msg)
iex> msg
%Msg{msg_k: %{1 => "foo", 2 => "bar"}}

iex> binary = <<66, 7, 8, 1, 18, 3, 102, 111, 66, 7, 8, 2, 18, 3, 98, 97, 114>>
iex> {:error, reason} = Protox.decode(binary, Msg)
iex> reason
%Protox.IllegalTagError{message: "Field with illegal tag 0"}
Link to this function

decode!(binary, msg_module)

View Source (since 1.6.0)

Specs

decode!(binary(), atom()) :: struct() | no_return()

Throwing version of decode/2.

Link to this function

encode(msg)

View Source (since 1.6.0)

Specs

encode(struct()) :: {:ok, iodata()} | {:error, any()}

Encode a protobuf message into IO data.

Examples

iex> msg = %Namespace.Fiz.Foo{a: 3, b: %{1 => %Namespace.Fiz.Baz{}}}
iex> {:ok, iodata} = Protox.encode(msg)
iex> :binary.list_to_bin(iodata)
<<8, 3, 18, 4, 8, 1, 18, 0>>

iex> msg = %Namespace.Fiz.Foo{a: "should not be a string"}
iex> {:error, reason} = Protox.encode(msg)
iex> reason
%Protox.EncodingError{field: :a, message: "Could not encode field :a (invalid field value)"}
Link to this function

encode!(msg)

View Source (since 1.6.0)

Specs

encode!(struct()) :: iodata() | no_return()

Throwing version of encode/1.

Link to this function

json_decode(input, message_module, opts \\ [])

View Source (since 1.6.0)

Specs

json_decode(iodata(), atom(), keyword()) :: {:ok, struct()} | {:error, any()}

Errors

This function returns a tuple {:error, reason} if:

JSON library configuration

The default library to decode JSON is Jason. However, you can chose to use Poison:

iex> Protox.json_decode("{\"a\":\"BAR\"}", Namespace.Fiz.Foo, json_decoder: Poison)
{:ok, %Namespace.Fiz.Foo{__uf__: [], a: :BAR, b: %{}}}

You can also use another library as long as it exports an decode! function. You can easily create a module to wrap a library that would not have this interface (like jiffy):

defmodule Jiffy do
  def decode!(input) do
    :jiffy.decode(input, [:return_maps, :use_nil])
  end
end
Link to this function

json_decode!(input, message_module, opts \\ [])

View Source (since 1.6.0)

Specs

json_decode!(iodata(), atom(), keyword()) :: iodata() | no_return()

Throwing version of json_decode/2.

Link to this function

json_encode(msg, opts \\ [])

View Source (since 1.6.0)

Specs

json_encode(struct(), keyword()) :: {:ok, iodata()} | {:error, any()}

Export a proto3 message to JSON as IO data.

Errors

This function returns a tuple {:error, reason} if:

Examples

iex> msg = %Namespace.Fiz.Foo{a: :BAR}
iex> {:ok, iodata} = Protox.json_encode(msg)
iex> iodata
["{", ["\"a\"", ":", "\"BAR\""], "}"]

iex> msg = %Sub{a: 42}
iex> {:ok, iodata} = Protox.json_encode(msg)
iex> iodata
["{", ["\"a\"", ":", "42"], "}"]

iex> msg = %Msg{msg_k: %{1 => "foo", 2 => "bar"}}
iex> {:ok, iodata} = msg |> Protox.json_encode()
iex> :binary.list_to_bin(iodata)
"{\"msgK\":{\"2\":\"bar\",\"1\":\"foo\"}}"

JSON library configuration

The default library to encode values (i.e. mostly to escape strings) to JSON is Jason. However, you can chose to use Poison:

iex> msg = %Namespace.Fiz.Foo{a: :BAR}
iex> Protox.json_encode(msg, json_encoder: Poison)
{:ok, ["{", ["\"a\"", ":", "\"BAR\""], "}"]}

You can also use another library as long as it exports an encode! function, which is expected to return objects as maps and nil to represent null. You can easily create a module to wrap a library that would not have this interface (like jiffy):

defmodule Jiffy do
  defdelegate encode!(msg), to: :jiffy, as: :encode
end

Encoding specifications

See https://developers.google.com/protocol-buffers/docs/proto3#json for the specifications of the encoding.

Link to this function

json_encode!(msg, opts \\ [])

View Source (since 1.6.0)

Specs

json_encode!(struct(), keyword()) :: iodata() | no_return()

Throwing version of json_encode/1.