Packages
avrora
0.30.0
0.30.2
0.30.1
0.30.0
0.29.2
0.29.1
0.29.0
0.28.0
0.27.0
0.26.0
0.25.0
0.24.2
0.24.1
0.24.0
0.23.0
0.22.0
0.21.1
0.21.0
0.20.0
0.19.0
0.18.1
0.18.0
0.17.0
0.16.0
0.15.0
0.14.1
0.14.0
0.13.0
0.12.0
0.11.0
0.10.0
0.9.1
0.9.0
0.8.1
0.8.0
0.7.1
0.7.0
0.6.0
0.5.1
0.5.0
0.4.0
0.3.1
0.3.0
0.2.2
0.2.1
0.2.0
0.1.1-beta
0.1.0-beta
An Elixir library for working with Avro messages conveniently. It supports local schema files and Confluent® schema registry.
Current section
Files
Jump to
Current section
Files
lib/avrora/codec/schema_registry.ex
defmodule Avrora.Codec.SchemaRegistry do
@moduledoc """
An Avro encoder/decoder working with a Schema Registry formatted Avro messages.
It works with a binary format, which includes a required schema global ID inside the message.
See more about [Schema Registry](https://docs.confluent.io/current/schema-registry/serializer-formatter.html#wire-format).
"""
@behaviour Avrora.Codec
@magic_bytes <<0::size(8)>>
require Logger
alias Avrora.Codec
alias Avrora.Resolver
alias Avrora.Schema
@impl true
def decodable?(payload) when is_binary(payload) do
case payload do
<<@magic_bytes, _::binary>> -> true
_ -> false
end
end
@impl true
def is_decodable(payload) when is_binary(payload) do
Logger.warning(
"`Avrora.Codec.SchemaRegistry.is_decodable/1` is deprecated, use `Avrora.Codec.SchemaRegistry.decodable?/1` instead"
)
decodable?(payload)
end
@impl true
def extract_schema(payload) when is_binary(payload) do
case payload do
<<@magic_bytes, <<id::size(32)>>, _::binary>> -> Resolver.resolve(id)
_ -> {:error, :schema_not_found}
end
end
@impl true
def decode(payload) when is_binary(payload) do
case payload do
<<@magic_bytes, <<id::size(32)>>, body::binary>> ->
with {:ok, schema} <- Resolver.resolve(id),
do: Codec.Plain.decode(body, schema: schema)
_ ->
{:error, :schema_not_found}
end
end
@impl true
def decode(payload, schema: schema) when is_binary(payload) do
case payload do
<<@magic_bytes, <<id::size(32)>>, body::binary>> ->
unless is_nil(schema.id) do
Logger.warning("message already contains embedded schema id, given schema id will be ignored")
end
schema = %Schema{schema | id: id}
with {:ok, schema} <- resolve(schema) do
if id != schema.id do
Logger.warning("message embedded schema id is different from the resolved and used schema id")
end
Codec.Plain.decode(body, schema: schema)
end
_ ->
{:error, :schema_not_found}
end
end
@impl true
def encode(payload, schema: schema) when is_binary(payload) or is_map(payload) do
with {:ok, schema} <- resolve(schema) do
schema = if is_nil(schema.id), do: {:error, :invalid_schema_id}, else: {:ok, schema}
with {:ok, schema} <- schema,
{:ok, body} <- Codec.Plain.encode(payload, schema: schema) do
encoded = <<@magic_bytes, <<schema.id::size(32)>>, body::binary>>
{:ok, encoded}
end
end
end
defp resolve(schema) do
cond do
is_integer(schema.id) && is_binary(schema.full_name) && is_reference(schema.lookup_table) ->
{:ok, schema}
is_integer(schema.id) && is_binary(schema.full_name) ->
Resolver.resolve_any([schema.id, schema.full_name])
is_integer(schema.id) ->
Resolver.resolve(schema.id)
is_binary(schema.full_name) ->
Resolver.resolve(schema.full_name)
true ->
{:error, :unusable_schema}
end
end
end