Skip to content

Commit a8c62d6

Browse files
committed
✨ Improve typesense sink endpoint url validation
1 parent 9c0c933 commit a8c62d6

File tree

2 files changed

+64
-2
lines changed

2 files changed

+64
-2
lines changed

lib/sequin/consumers/typesense_sink.ex

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,23 @@ defmodule Sequin.Consumers.TypesenseSink do
3333
changeset
3434
|> validate_change(:endpoint_url, fn :endpoint_url, url ->
3535
case URI.parse(url) do
36-
%URI{scheme: scheme, host: host} when not is_nil(scheme) and not is_nil(host) -> []
37-
_ -> [endpoint_url: "must be a valid URL"]
36+
%URI{scheme: nil} ->
37+
[endpoint_url: "must include a scheme, ie. https://"]
38+
39+
%URI{scheme: scheme} when scheme not in ["http", "https"] ->
40+
[endpoint_url: "must include a valid scheme, ie. http or https"]
41+
42+
%URI{host: host} when is_nil(host) or host == "" ->
43+
[endpoint_url: "must include a host"]
44+
45+
%URI{query: query} when not is_nil(query) ->
46+
[endpoint_url: "must not include query params, found: #{query}"]
47+
48+
%URI{fragment: fragment} when not is_nil(fragment) ->
49+
[endpoint_url: "must not include a fragment, found: #{fragment}"]
50+
51+
_ ->
52+
[]
3853
end
3954
end)
4055
|> validate_length(:endpoint_url, max: 4096)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
defmodule Sequin.Consumers.TypesenseSinkTest do
2+
use ExUnit.Case, async: true
3+
4+
alias Sequin.Consumers.TypesenseSink
5+
6+
describe "changeset/2" do
7+
setup do
8+
%{
9+
valid_params: %{
10+
endpoint_url: "https://typesense.com",
11+
collection_name: "test",
12+
api_key: "test"
13+
}
14+
}
15+
end
16+
17+
test "valid params have no errors", %{valid_params: params} do
18+
changeset = TypesenseSink.changeset(%TypesenseSink{}, params)
19+
assert Sequin.Error.errors_on(changeset) == %{}
20+
end
21+
22+
test "validates endpoint_url with missing scheme", %{valid_params: params} do
23+
changeset = TypesenseSink.changeset(%TypesenseSink{}, %{params | endpoint_url: "invalid"})
24+
assert Sequin.Error.errors_on(changeset)[:endpoint_url] == ["must include a scheme, ie. https://"]
25+
end
26+
27+
test "validates endpoint_url with invalid scheme", %{valid_params: params} do
28+
changeset = TypesenseSink.changeset(%TypesenseSink{}, %{params | endpoint_url: "ftp://typesense.com"})
29+
assert Sequin.Error.errors_on(changeset)[:endpoint_url] == ["must include a valid scheme, ie. http or https"]
30+
end
31+
32+
test "validates endpoint_url with missing host", %{valid_params: params} do
33+
changeset = TypesenseSink.changeset(%TypesenseSink{}, %{params | endpoint_url: "https://"})
34+
assert Sequin.Error.errors_on(changeset)[:endpoint_url] == ["must include a host"]
35+
end
36+
37+
test "validates endpoint_url with query params", %{valid_params: params} do
38+
changeset = TypesenseSink.changeset(%TypesenseSink{}, %{params | endpoint_url: "https://typesense.com?param=value"})
39+
assert Sequin.Error.errors_on(changeset)[:endpoint_url] == ["must not include query params, found: param=value"]
40+
end
41+
42+
test "validates endpoint_url with fragment", %{valid_params: params} do
43+
changeset = TypesenseSink.changeset(%TypesenseSink{}, %{params | endpoint_url: "https://typesense.com#fragment"})
44+
assert Sequin.Error.errors_on(changeset)[:endpoint_url] == ["must not include a fragment, found: fragment"]
45+
end
46+
end
47+
end

0 commit comments

Comments
 (0)