Skip to content

Commit 935bddb

Browse files
authored
Add User-Agent header when requesting registry (#100)
Closes #101
1 parent 7c16576 commit 935bddb

File tree

8 files changed

+61
-9
lines changed

8 files changed

+61
-9
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
[v0.22]: https://github.com/Strech/avrora/releases/tag/v0.22.0
2323
[v0.23]: https://github.com/Strech/avrora/releases/tag/v0.23.0
2424
[v0.24]: https://github.com/Strech/avrora/releases/tag/v0.24.0
25+
[v0.25]: https://github.com/Strech/avrora/releases/tag/v0.25.0
2526
[1]: https://avro.apache.org/
2627
[2]: https://www.confluent.io/confluent-schema-registry
2728
[3]: https://docs.confluent.io/current/schema-registry/serializer-formatter.html#wire-format
@@ -84,6 +85,7 @@ defmodule MyClient do
8485
otp_app: :my_application,
8586
registry_url: "http://localhost:8081",
8687
registry_auth: {:basic, ["username", "password"]},
88+
registry_user_agent: "Avrora/0.25.0 Elixir",
8789
schemas_path: "./priv/schemas",
8890
registry_schemas_autoreg: false,
8991
convert_null_values: false,
@@ -104,6 +106,7 @@ config :avrora,
104106
otp_app: :my_application, # optional, if you want to use it as a root folder for `schemas_path`
105107
registry_url: "http://localhost:8081",
106108
registry_auth: {:basic, ["username", "password"]}, # optional
109+
registry_user_agent: "Avrora/0.24.2 Elixir", # optional: if you want to return previous behaviour, set it to `nil`
107110
schemas_path: "./priv/schemas",
108111
registry_schemas_autoreg: false, # optional: if you want manually register schemas
109112
convert_null_values: false, # optional: if you want to keep decoded `:null` values as is
@@ -115,6 +118,7 @@ config :avrora,
115118
- `otp_app`<sup>[v0.22]</sup> - Name of the OTP application to use for runtime configuration via env, default `nil`
116119
- `registry_url` - URL for the Schema Registry, default `nil`
117120
- `registry_auth` – Credentials to authenticate in the Schema Registry, default `nil`
121+
- `registry_user_agent`<sup>[v0.25]</sup> - HTTP `User-Agent` header for Schema Registry requests, default `Avrora/<version> Elixir`
118122
- `schemas_path` - Base path for locally stored schema files, default `./priv/schemas`
119123
- `registry_schemas_autoreg`<sup>[v0.13]</sup> - Flag for automatic schemas registration in the Schema Registry, default `true`
120124
- `convert_null_values`<sup>[v0.14]</sup> - Flag for automatic conversion of decoded `:null` values into `nil`, default `true`

config/config.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ config :avrora,
44
schemas_path: Path.expand("./test/fixtures/schemas"),
55
registry_url: nil,
66
registry_auth: nil,
7+
registry_user_agent: nil,
78
registry_schemas_autoreg: true,
89
convert_null_values: true,
910
names_cache_ttl: :infinity

lib/avrora/client.ex

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ defmodule Avrora.Client do
111111

112112
def registry_url, do: get(@opts, :registry_url, nil)
113113
def registry_auth, do: get(@opts, :registry_auth, nil)
114+
def registry_user_agent, do: get(@opts, :registry_user_agent, "Avrora/#{version()} Elixir")
114115
def registry_schemas_autoreg, do: get(@opts, :registry_schemas_autoreg, true)
115116
def convert_null_values, do: get(@opts, :convert_null_values, true)
116117
def convert_map_to_proplist, do: get(@opts, :convert_map_to_proplist, false)
@@ -122,6 +123,8 @@ defmodule Avrora.Client do
122123
def http_client, do: Avrora.HTTPClient
123124
def ets_lib, do: :"Elixir.#{unquote(module)}.AvroSchemaStore"
124125

126+
defp version, do: Application.spec(:avrora, :vsn)
127+
125128
if is_nil(@otp_app) do
126129
def self, do: __MODULE__
127130

lib/avrora/config.ex

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ defmodule Avrora.Config do
88
* `schemas_path` path to local schema files, default `./priv/schemas`
99
* `registry_url` URL for Schema Registry, default `nil`
1010
* `registry_auth` authentication settings for Schema Registry, default `nil`
11+
* `registry_user_agent` HTTP `User-Agent` header for Schema Registry requests, default `Avrora/<version> Elixir`
1112
* `registry_schemas_autoreg` automatically register schemas in Schema Registry, default `true`
1213
* `convert_null_values` convert `:null` values in the decoded message into `nil`, default `true`
1314
* `convert_map_to_proplist` bring back old behavior and configure decoding AVRO map-type as proplist, default `false`
@@ -26,6 +27,7 @@ defmodule Avrora.Config do
2627
@callback schemas_path :: String.t()
2728
@callback registry_url :: String.t() | nil
2829
@callback registry_auth :: tuple() | nil
30+
@callback registry_user_agent :: String.t() | nil
2931
@callback registry_schemas_autoreg :: boolean()
3032
@callback convert_null_values :: boolean()
3133
@callback convert_map_to_proplist :: boolean()
@@ -51,6 +53,9 @@ defmodule Avrora.Config do
5153
@doc false
5254
def registry_auth, do: get_env(:registry_auth, nil)
5355

56+
@doc false
57+
def registry_user_agent, do: get_env(:registry_user_agent, "Avrora/#{version()} Elixir")
58+
5459
@doc false
5560
def registry_schemas_autoreg, do: get_env(:registry_schemas_autoreg, true)
5661

@@ -85,4 +90,5 @@ defmodule Avrora.Config do
8590
def self, do: get_env(:config, Avrora.Config)
8691

8792
defp get_env(name, default), do: Application.get_env(:avrora, name, default)
93+
defp version, do: Application.spec(:avrora, :vsn)
8894
end

lib/avrora/http_client.ex

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,15 @@ defmodule Avrora.HTTPClient do
2828
end
2929

3030
defp extract_headers(options) do
31-
case Keyword.get(options, :authorization) do
32-
nil -> {:ok, []}
33-
credentials -> {:ok, [{'Authorization', '#{credentials}'}]}
31+
authorization =
32+
case Keyword.get(options, :authorization) do
33+
nil -> []
34+
credentials -> [{'Authorization', '#{credentials}'}]
35+
end
36+
37+
case Keyword.get(options, :user_agent) do
38+
nil -> {:ok, authorization}
39+
user_agent -> {:ok, [{'User-Agent', '#{user_agent}'} | authorization]}
3440
end
3541
end
3642

lib/avrora/storage/registry.ex

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,19 @@ defmodule Avrora.Storage.Registry do
131131

132132
# NOTE: Maybe move to compile-time?
133133
defp headers do
134-
case registry_auth() do
135-
{:basic, [username, password]} ->
136-
credentials = :base64.encode("#{username}:#{password}")
137-
[authorization: "Basic #{credentials}"]
134+
authorization =
135+
case registry_auth() do
136+
{:basic, [username, password]} ->
137+
credentials = :base64.encode("#{username}:#{password}")
138+
[authorization: "Basic #{credentials}"]
139+
140+
nil ->
141+
[]
142+
end
138143

139-
nil ->
140-
[]
144+
case registry_user_agent() do
145+
nil -> authorization
146+
user_agent -> authorization |> Keyword.put(:user_agent, user_agent)
141147
end
142148
end
143149

@@ -162,4 +168,5 @@ defmodule Avrora.Storage.Registry do
162168
defp http_client, do: Config.self().http_client()
163169
defp registry_url, do: Config.self().registry_url()
164170
defp registry_auth, do: Config.self().registry_auth()
171+
defp registry_user_agent, do: Config.self().registry_user_agent()
165172
end

test/avrora/storage/registry_test.exs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,29 @@ defmodule Avrora.Storage.RegistryTest do
292292
assert schema.full_name == "io.confluent.Payment"
293293
end
294294

295+
test "when request with user agent was successful" do
296+
stub(Avrora.ConfigMock, :registry_user_agent, fn -> "Avrora/0.0.1 Elixir" end)
297+
298+
Avrora.HTTPClientMock
299+
|> expect(:post, fn url, payload, options ->
300+
assert url == "http://reg.loc/subjects/io.confluent.Payment/versions"
301+
assert payload == json_schema()
302+
303+
assert options == [
304+
content_type: "application/vnd.schemaregistry.v1+json",
305+
user_agent: "Avrora/0.0.1 Elixir"
306+
]
307+
308+
{:ok, %{"id" => 1}}
309+
end)
310+
311+
{:ok, schema} = Registry.put("io.confluent.Payment", json_schema())
312+
313+
assert schema.id == 1
314+
assert is_nil(schema.version)
315+
assert schema.full_name == "io.confluent.Payment"
316+
end
317+
295318
test "when key contains version and request was successful" do
296319
Avrora.HTTPClientMock
297320
|> expect(:post, fn url, payload, _ ->

test/support/config.ex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ defmodule Support.Config do
4040
@impl true
4141
def registry_auth, do: nil
4242
@impl true
43+
def registry_user_agent, do: nil
44+
@impl true
4345
def registry_schemas_autoreg, do: true
4446
@impl true
4547
def convert_null_values, do: true

0 commit comments

Comments
 (0)