Skip to content

Commit 08e1c5d

Browse files
feat: Improve config
1 parent c206d94 commit 08e1c5d

File tree

3 files changed

+123
-56
lines changed

3 files changed

+123
-56
lines changed

lib/posthog/application.ex

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ defmodule Posthog.Application do
88
def cache_name, do: @cache_name
99

1010
def start(_type, args) do
11+
# Validate configuration before starting
12+
Posthog.Config.validate_config!()
13+
1114
cache_name = Keyword.get(args, :cache_name, @cache_name)
1215

1316
children = [

lib/posthog/client.ex

Lines changed: 6 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,6 @@ defmodule Posthog.Client do
6767
Posthog.Client.feature_flags("user_123", groups: %{team: "engineering"})
6868
"""
6969

70-
@app :posthog
71-
7270
@typedoc """
7371
HTTP headers in the format expected by :hackney.
7472
"""
@@ -171,7 +169,7 @@ defmodule Posthog.Client do
171169
@spec capture(event(), distinct_id(), properties(), opts()) ::
172170
{:ok, response()} | {:error, response() | term()}
173171
def capture(event, distinct_id, properties \\ %{}, opts \\ []) when is_list(opts) do
174-
if enabled_capture?() do
172+
if Posthog.Config.enabled_capture?() do
175173
timestamp =
176174
Keyword.get_lazy(opts, :timestamp, fn ->
177175
DateTime.utc_now() |> DateTime.to_iso8601()
@@ -214,7 +212,7 @@ defmodule Posthog.Client do
214212
end
215213

216214
def batch(events, opts, headers) do
217-
if enabled_capture?() do
215+
if Posthog.Config.enabled_capture?() do
218216
timestamp = Keyword.get_lazy(opts, :timestamp, fn -> DateTime.utc_now() end)
219217

220218
body =
@@ -362,10 +360,10 @@ defmodule Posthog.Client do
362360
defp post!(path, %{} = body, headers) do
363361
body =
364362
body
365-
|> Map.put(:api_key, api_key())
366-
|> encode(json_library())
363+
|> Map.put(:api_key, Posthog.Config.api_key())
364+
|> encode(Posthog.Config.json_library())
367365

368-
url = api_url() <> path
366+
url = Posthog.Config.api_url() <> path
369367

370368
:hackney.post(url, headers, body, [])
371369
|> handle()
@@ -391,56 +389,14 @@ defmodule Posthog.Client do
391389
response = %{status: status, headers: headers, body: nil}
392390

393391
with {:ok, body} <- :hackney.body(ref),
394-
{:ok, json} <- json_library().decode(body) do
392+
{:ok, json} <- Posthog.Config.json_library().decode(body) do
395393
%{response | body: json}
396394
else
397395
_ -> response
398396
end
399397
end
400398

401399
@doc false
402-
@spec api_url() :: binary()
403-
defp api_url do
404-
case Application.get_env(@app, :api_url) do
405-
url when is_bitstring(url) ->
406-
url
407-
408-
term ->
409-
raise """
410-
Expected a string API URL, got: #{inspect(term)}. Set a
411-
URL and key in your config:
412-
413-
config :posthog,
414-
api_url: "https://posthog.example.com",
415-
api_key: "my-key"
416-
"""
417-
end
418-
end
419-
420-
@doc false
421-
@spec api_key() :: binary()
422-
defp api_key do
423-
case Application.get_env(@app, :api_key) do
424-
key when is_bitstring(key) ->
425-
key
426-
427-
term ->
428-
raise """
429-
Expected a string API key, got: #{inspect(term)}. Set a
430-
URL and key in your config:
431-
432-
config :posthog,
433-
api_url: "https://posthog.example.com",
434-
api_key: "my-key"
435-
"""
436-
end
437-
end
438-
439-
@doc false
440-
defp enabled_capture? do
441-
Application.get_env(@app, :enabled_capture, true)
442-
end
443-
444400
defp disabled_capture_response do
445401
{:ok, %{status: 200, headers: [], body: nil}}
446402
end
@@ -450,12 +406,6 @@ defmodule Posthog.Client do
450406
defp encode(data, Jason), do: Jason.encode_to_iodata!(data)
451407
defp encode(data, library), do: library.encode!(data)
452408

453-
@doc false
454-
@spec json_library() :: module()
455-
defp json_library do
456-
Application.get_env(@app, :json_library, Jason)
457-
end
458-
459409
@doc false
460410
@spec lib_properties() :: map()
461411
defp lib_properties do

lib/posthog/config.ex

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
defmodule Posthog.Config do
2+
@moduledoc """
3+
Handles configuration validation and defaults for the PostHog client.
4+
5+
This module validates the configuration at compile time and provides
6+
sensible defaults for optional values.
7+
"""
8+
9+
@app :posthog
10+
11+
@doc """
12+
Validates and returns the API URL from the configuration.
13+
14+
Raises a helpful error message if the URL is missing or invalid.
15+
"""
16+
def api_url do
17+
case Application.get_env(@app, :api_url) do
18+
url when is_binary(url) and url != "" ->
19+
url
20+
21+
nil ->
22+
raise """
23+
PostHog API URL is not configured. Please add it to your config:
24+
25+
config :posthog,
26+
api_url: "https://app.posthog.com" # or your self-hosted instance
27+
"""
28+
29+
url ->
30+
raise """
31+
Invalid PostHog API URL: #{inspect(url)}
32+
33+
Expected a non-empty string URL, for example:
34+
config :posthog,
35+
api_url: "https://app.posthog.com" # or your self-hosted instance
36+
"""
37+
end
38+
end
39+
40+
@doc """
41+
Validates and returns the API key from the configuration.
42+
43+
Raises a helpful error message if the key is missing or invalid.
44+
"""
45+
def api_key do
46+
case Application.get_env(@app, :api_key) do
47+
key when is_binary(key) and key != "" ->
48+
key
49+
50+
nil ->
51+
raise """
52+
PostHog API key is not configured. Please add it to your config:
53+
54+
config :posthog,
55+
api_key: "phc_your_project_api_key"
56+
"""
57+
58+
key ->
59+
raise """
60+
Invalid PostHog API key: #{inspect(key)}
61+
62+
Expected a non-empty string API key, for example:
63+
config :posthog,
64+
api_key: "phc_your_project_api_key"
65+
"""
66+
end
67+
end
68+
69+
@doc """
70+
Returns whether event capture is enabled.
71+
72+
Defaults to true if not configured.
73+
"""
74+
def enabled_capture? do
75+
Application.get_env(@app, :enabled_capture, true)
76+
end
77+
78+
@doc """
79+
Returns the JSON library to use for encoding/decoding.
80+
81+
Defaults to Jason if not configured.
82+
"""
83+
def json_library do
84+
Application.get_env(@app, :json_library, Jason)
85+
end
86+
87+
@doc """
88+
Validates the entire PostHog configuration at compile time.
89+
90+
This ensures that all required configuration is present and valid
91+
before the application starts.
92+
"""
93+
def validate_config! do
94+
# Validate required config
95+
api_url()
96+
api_key()
97+
98+
# Validate optional config
99+
if json_library() != Jason do
100+
unless Code.ensure_loaded?(json_library()) do
101+
raise """
102+
Configured JSON library #{inspect(json_library())} is not available.
103+
104+
Make sure to add it to your dependencies in mix.exs:
105+
defp deps do
106+
[{#{inspect(json_library())}, "~> x.x"}]
107+
end
108+
"""
109+
end
110+
end
111+
112+
:ok
113+
end
114+
end

0 commit comments

Comments
 (0)