Skip to content

Commit e7b2ff9

Browse files
emyllerclaude
andcommitted
feat: add User-Agent header with SDK version
- Add user_agent/0 function to dynamically retrieve SDK version from Application.spec - Format: flagsmith-elixir-sdk/<version> or flagsmith-elixir-sdk/unknown as fallback - Add user_agent_middleware/0 to inject User-Agent header in all HTTP requests - Add comprehensive tests with semver validation using Version.parse/1 - Follows the pattern established in Go and Java Flagsmith SDKs Co-authored-by: Claude Code <[email protected]>
1 parent 587d126 commit e7b2ff9

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

lib/flagsmith_client.ex

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ defmodule Flagsmith.Client do
88
@type tesla_header_list :: [{String.t(), String.t()}]
99
@type config_or_env :: Configuration.t() | Keyword.t() | Schemas.Environment.t()
1010

11+
@doc false
12+
@spec user_agent() :: String.t()
13+
def user_agent do
14+
case Application.spec(:flagsmith_engine, :vsn) do
15+
nil -> "flagsmith-elixir-sdk/unknown"
16+
vsn -> "flagsmith-elixir-sdk/#{vsn}"
17+
end
18+
end
19+
1120
@doc """
1221
Create a `t:Flagsmith.Configuration.t/0` struct with the desired settings to use
1322
in requests.
@@ -31,6 +40,7 @@ defmodule Flagsmith.Client do
3140
Tesla.client([
3241
base_url_middleware(api_url),
3342
auth_middleware(environment_key),
43+
user_agent_middleware(),
3444
Tesla.Middleware.JSON,
3545
{Tesla.Middleware.Retry, max_retries: retries},
3646
{Tesla.Middleware.Headers, custom_headers},
@@ -394,6 +404,12 @@ defmodule Flagsmith.Client do
394404
def auth_middleware(environment_key),
395405
do: {Tesla.Middleware.Headers, auth_header(environment_key)}
396406

407+
@doc false
408+
@spec user_agent_middleware() ::
409+
{Tesla.Middleware.Headers, tesla_header_list()}
410+
def user_agent_middleware(),
411+
do: {Tesla.Middleware.Headers, [{"user-agent", user_agent()}]}
412+
397413
@doc false
398414
@spec base_url_middleware(base_url :: String.t()) ::
399415
{Tesla.Middleware.BaseUrl, String.t()}

test/flagsmith_client_test.exs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,4 +437,35 @@ defmodule Flagsmith.Client.Test do
437437
Flagsmith.Client.get_flag(new_config, "some_flag")
438438
end
439439
end
440+
441+
describe "User-Agent header" do
442+
test "user_agent/0 returns valid semver version" do
443+
user_agent = Flagsmith.Client.user_agent()
444+
version_part = String.replace_prefix(user_agent, "flagsmith-elixir-sdk/", "")
445+
446+
assert {:ok, parsed} = Version.parse(version_part)
447+
assert is_integer(parsed.major) and parsed.major >= 0
448+
assert is_integer(parsed.minor) and parsed.minor >= 0
449+
assert is_integer(parsed.patch) and parsed.patch >= 0
450+
end
451+
452+
test "HTTP client includes User-Agent header with valid semver", %{config: config} do
453+
expect(Tesla.Adapter.Mock, :call, fn tesla_env, _options ->
454+
user_agent_header =
455+
Enum.find(tesla_env.headers, fn {header, _} ->
456+
header == "user-agent"
457+
end)
458+
459+
assert user_agent_header != nil
460+
{_header, user_agent_value} = user_agent_header
461+
462+
version_part = String.replace_prefix(user_agent_value, "flagsmith-elixir-sdk/", "")
463+
assert {:ok, _} = Version.parse(version_part)
464+
465+
{:ok, %Tesla.Env{status: 200, body: Test.Generators.map_env()}}
466+
end)
467+
468+
Flagsmith.Client.get_environment(config)
469+
end
470+
end
440471
end

0 commit comments

Comments
 (0)