Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ All notable changes to this project will be documented in this file.

### Fixed

- `Zoi.url/1` now accepts non-HTTP URI schemes
- `Zoi.from_json_schema/1` now accepts quoted email local parts
- `Zoi.float/1` now coerces integer inputs when coercion is enabled
- `Zoi.from_json_schema/1` now preserves sibling constraints alongside combinators, `enum` and `const`
- `Zoi.from_json_schema/1` now enforces exactly one match for `oneOf` and accepts single-branch combinators
Expand Down
2 changes: 1 addition & 1 deletion lib/zoi/json_schema/decoder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ defmodule Zoi.JSONSchema.Decoder do
"date" -> Zoi.ISO.date()
"time" -> Zoi.ISO.time()
"date-time" -> Zoi.ISO.datetime()
"email" -> Zoi.email()
"email" -> Zoi.email(pattern: Zoi.Regexes.rfc5322_email())
"uri" -> Zoi.url()
"uuid" -> Zoi.uuid()
_ -> Zoi.string()
Expand Down
2 changes: 1 addition & 1 deletion lib/zoi/types/string.ex
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ defmodule Zoi.Types.String do
def validate(_schema, input, opts) do
uri = URI.parse(input)

if uri.scheme in ["http", "https"] and uri.host != nil do
if uri.scheme != nil do
:ok
else
{:error, Zoi.Error.invalid_url(input, opts)}
Expand Down
18 changes: 18 additions & 0 deletions test/zoi/json_schema_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,24 @@ defmodule Zoi.JSONSchemaTest do
end)
end

test "decodes URI and email formats without HTTP or unquoted-local-part restrictions" do
uri_schema = Zoi.from_json_schema(%{"type" => "string", "format" => "uri"})

for uri <- ["mailto:user@example.com", "urn:isbn:0451450523", "ftp://example.com/file"] do
assert {:ok, ^uri} = Zoi.parse(uri_schema, uri)
end

for invalid <- ["", "relative/path", "://example.com"] do
assert {:error, _} = Zoi.parse(uri_schema, invalid)
end

email_schema = Zoi.from_json_schema(%{"type" => "string", "format" => "email"})
email = ~s("John Doe"@example.com)
assert {:ok, ^email} = Zoi.parse(email_schema, email)
assert {:error, _} = Zoi.parse(email_schema, "invalid-email")
assert {:error, _} = Zoi.parse(Zoi.email(), email)
end

test "decodes constraints and rejects invalid values" do
cases = [
{%{"type" => "string", "minLength" => 2, "maxLength" => 5}, "abc", ["a", "abcdef"]},
Expand Down
21 changes: 15 additions & 6 deletions test/zoi_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3768,8 +3768,17 @@ defmodule ZoiTest do
describe "url/0" do
test "valid URL" do
schema = Zoi.url()
assert {:ok, "https://example.com"} == Zoi.parse(schema, "https://example.com")
assert {:ok, "https://example.com"} == Zoi.parse(schema, "https://example.com")

for url <- [
"https://example.com",
"mailto:user@example.com",
"urn:isbn:0451450523",
"ftp://example.com/file",
"custom:resource"
] do
assert {:ok, ^url} = Zoi.parse(schema, url)
end

assert {:ok, "http://localhost"} == Zoi.parse(schema, "http://localhost")

assert {:ok, "https://google.com/Foo%20Bar"} ==
Expand All @@ -3780,10 +3789,10 @@ defmodule ZoiTest do
schema = Zoi.url()

invalid_urls = [
"htp://invalid-protocol.com",
"",
"://missing-protocol.com",
"http//missing-colon.com",
"http:/one-slash.com",
"relative/path",
"/?foo[bar]=baz"
]

Expand All @@ -3797,10 +3806,10 @@ defmodule ZoiTest do

test "invalid url with custom eror" do
schema = Zoi.url(error: "something went wrong with the url")
assert {:error, [%Zoi.Error{} = error]} = Zoi.parse(schema, "htt://google/com")
assert {:error, [%Zoi.Error{} = error]} = Zoi.parse(schema, "://google/com")
assert error.code == :custom
assert Exception.message(error) == "something went wrong with the url"
assert {"something went wrong with the url", [value: "htt://google/com"]} = error.issue
assert {"something went wrong with the url", [value: "://google/com"]} = error.issue
end

test "url should only work on implemented protocols" do
Expand Down
Loading