Packages
zoi
0.7.1
0.18.6
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.1
0.16.0
0.15.0
0.14.1
0.14.0
0.13.1
0.13.0
0.12.1
0.12.0
0.11.1
0.11.0
0.10.7
0.10.6
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.1
0.9.0
0.9.0-rc.1
0.9.0-rc.0
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.0
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.3
0.1.2
0.1.1
0.1.0
Zoi is a schema validation library for Elixir, designed to provide a simple and flexible way to define and validate data.
Current section
74 Versions
Jump to
Current section
74 Versions
Compare versions
5
files changed
+101
additions
-22
deletions
| @@ -2,6 +2,13 @@ | |
| 2 2 | |
| 3 3 | All notable changes to this project will be documented in this file. |
| 4 4 | |
| 5 | + ## 0.7.1 - 2025-10-12 |
| 6 | + |
| 7 | + ### Added |
| 8 | + |
| 9 | + - `Zoi.to_json_schema/1` support for metadata (e.g., example, description) |
| 10 | + - `guides/quickstart_guide.md` added to the documentation |
| 11 | + |
| 5 12 | ## 0.7.0 - 2025-10-10 |
| 6 13 | |
| 7 14 | ### Added |
| @@ -195,6 +195,16 @@ defmodule MyApp.UserSchemaTest do | |
| 195 195 | end |
| 196 196 | ``` |
| 197 197 | |
| 198 | + ## Guides |
| 199 | + |
| 200 | + Check the official guides for more examples and use cases: |
| 201 | + |
| 202 | + - [Quickstart Guide](https://hexdocs.pm/zoi/quickstart_guide.html) |
| 203 | + - [Using Zoi to generate OpenAPI specs](https://hexdocs.pm/zoi/using_zoi_to_generate_openapi_specs.html) |
| 204 | + - [Validating controller parameters](https://hexdocs.pm/zoi/validating_controller_parameters.html) |
| 205 | + - [Converting Keys From Object](https://hexdocs.pm/zoi/converting_keys_from_object.html) |
| 206 | + - [Generating Schemas from JSON](https://hexdocs.pm/zoi/generating_schemas_from_json_example.html) |
| 207 | + |
| 198 208 | ## Acknowledgements |
| 199 209 | |
| 200 210 | `Zoi` is inspired by [Zod](https://zod.dev/) and [Joi](https://joi.dev/), providing a similar experience for Elixir. |
| @@ -2,7 +2,7 @@ | |
| 2 2 | [{<<"Changelog">>,<<"https://hexdocs.pm/zoi/changelog.html">>}, |
| 3 3 | {<<"GitHub">>,<<"https://github.com/phcurado/zoi">>}]}. |
| 4 4 | {<<"name">>,<<"zoi">>}. |
| 5 | - {<<"version">>,<<"0.7.0">>}. |
| 5 | + {<<"version">>,<<"0.7.1">>}. |
| 6 6 | {<<"description">>, |
| 7 7 | <<"Zoi is a schema validation library for Elixir, designed to provide a simple and flexible way to define and validate data.">>}. |
| 8 8 | {<<"elixir">>,<<"~> 1.14">>}. |
| @@ -9,7 +9,7 @@ defmodule Zoi.JSONSchema do | |
| 9 9 | iex> schema = Zoi.object(%{name: Zoi.string(), age: Zoi.integer()}) |
| 10 10 | iex> Zoi.to_json_schema(schema) |
| 11 11 | %{ |
| 12 | - "$schema" => "https://json-schema.org/draft/2020-12/schema", |
| 12 | + "$schema": "https://json-schema.org/draft/2020-12/schema", |
| 13 13 | type: :object, |
| 14 14 | properties: %{ |
| 15 15 | name: %{type: :string}, |
| @@ -43,6 +43,24 @@ defmodule Zoi.JSONSchema do | |
| 43 43 | - `Zoi.naive_datetime/0` and `Zoi.ISO.naive_datetime/0` |
| 44 44 | - `Zoi.time/0` and `Zoi.ISO.time/0` |
| 45 45 | |
| 46 | + ## Metadata |
| 47 | + `Zoi.to_json_schema/1` will attempt to parse metadata defined on types. For more information, check the `Zoi.metadata/1` documentation. |
| 48 | + The following metadata will be parsed on JSON Schema conversion: |
| 49 | + |
| 50 | + - `:description` - Adds a `description` field to the JSON Schema. |
| 51 | + - `:example` - Adds an `example` field to the JSON Schema. |
| 52 | + |
| 53 | + ```elixir |
| 54 | + iex> schema = Zoi.string(metadata: [description: "A simple string", example: "Hello, World!"]) |
| 55 | + iex> Zoi.to_json_schema(schema) |
| 56 | + %{ |
| 57 | + "$schema": "https://json-schema.org/draft/2020-12/schema", |
| 58 | + type: :string, |
| 59 | + description: "A simple string", |
| 60 | + example: "Hello, World!" |
| 61 | + } |
| 62 | + ``` |
| 63 | + |
| 46 64 | ## Limitations |
| 47 65 | |
| 48 66 | - Complex types or custom types not listed above will raise an error during conversion. |
| @@ -72,36 +90,43 @@ defmodule Zoi.JSONSchema do | |
| 72 90 | |
| 73 91 | defp encode_schema(%Zoi.Types.String{} = schema) do |
| 74 92 | %{type: :string} |
| 93 | + |> encode_metadata(schema) |
| 75 94 | |> encode_refinements(schema.meta) |
| 76 95 | end |
| 77 96 | |
| 78 97 | defp encode_schema(%Zoi.Types.Integer{} = schema) do |
| 79 98 | %{type: :integer} |
| 99 | + |> encode_metadata(schema) |
| 80 100 | |> encode_refinements(schema.meta) |
| 81 101 | end |
| 82 102 | |
| 83 103 | defp encode_schema(%Zoi.Types.Float{} = schema) do |
| 84 104 | %{type: :number} |
| 105 | + |> encode_metadata(schema) |
| 85 106 | |> encode_refinements(schema.meta) |
| 86 107 | end |
| 87 108 | |
| 88 109 | defp encode_schema(%Zoi.Types.Number{} = schema) do |
| 89 110 | %{type: :number} |
| 111 | + |> encode_metadata(schema) |
| 90 112 | |> encode_refinements(schema.meta) |
| 91 113 | end |
| 92 114 | |
| 93 | - defp encode_schema(%Zoi.Types.Boolean{}) do |
| 115 | + defp encode_schema(%Zoi.Types.Boolean{} = schema) do |
| 94 116 | %{type: :boolean} |
| 117 | + |> encode_metadata(schema) |
| 95 118 | end |
| 96 119 | |
| 97 | - defp encode_schema(%Zoi.Types.Literal{value: value}) do |
| 120 | + defp encode_schema(%Zoi.Types.Literal{value: value} = schema) do |
| 98 121 | %{ |
| 99 122 | const: value |
| 100 123 | } |
| 124 | + |> encode_metadata(schema) |
| 101 125 | end |
| 102 126 | |
| 103 | - defp encode_schema(%Zoi.Types.Null{}) do |
| 127 | + defp encode_schema(%Zoi.Types.Null{} = schema) do |
| 104 128 | %{type: :null} |
| 129 | + |> encode_metadata(schema) |
| 105 130 | end |
| 106 131 | |
| 107 132 | defp encode_schema(%Zoi.Types.Array{inner: inner} = schema) do |
| @@ -110,6 +135,7 @@ defmodule Zoi.JSONSchema do | |
| 110 135 | %{ |
| 111 136 | type: :array |
| 112 137 | } |
| 138 | + |> encode_metadata(schema) |
| 113 139 | |> encode_refinements(schema.meta) |
| 114 140 | |
| 115 141 | _inner -> |
| @@ -117,6 +143,7 @@ defmodule Zoi.JSONSchema do | |
| 117 143 | type: :array, |
| 118 144 | items: encode_schema(inner) |
| 119 145 | } |
| 146 | + |> encode_metadata(schema) |
| 120 147 | |> encode_refinements(schema.meta) |
| 121 148 | end |
| 122 149 | end |
| @@ -126,6 +153,7 @@ defmodule Zoi.JSONSchema do | |
| 126 153 | type: :array, |
| 127 154 | prefixItems: Enum.map(schema.fields, &encode_schema/1) |
| 128 155 | } |
| 156 | + |> encode_metadata(schema) |
| 129 157 | |> encode_refinements(schema.meta) |
| 130 158 | end |
| 131 159 | |
| @@ -134,12 +162,14 @@ defmodule Zoi.JSONSchema do | |
| 134 162 | type: :string, |
| 135 163 | enum: Enum.map(schema.values, fn {_k, v} -> v end) |
| 136 164 | } |
| 165 | + |> encode_metadata(schema) |
| 137 166 | end |
| 138 167 | |
| 139 | - defp encode_schema(%Zoi.Types.Map{}) do |
| 168 | + defp encode_schema(%Zoi.Types.Map{} = schema) do |
| 140 169 | %{ |
| 141 170 | type: :object |
| 142 171 | } |
| 172 | + |> encode_metadata(schema) |
| 143 173 | end |
| 144 174 | |
| 145 175 | defp encode_schema(%Zoi.Types.Object{} = schema) do |
| @@ -154,50 +184,61 @@ defmodule Zoi.JSONSchema do | |
| 154 184 | |> Enum.map(fn {k, _v} -> k end), |
| 155 185 | additionalProperties: false |
| 156 186 | } |
| 187 | + |> encode_metadata(schema) |
| 157 188 | end |
| 158 189 | |
| 159 | - defp encode_schema(%Zoi.Types.Intersection{schemas: schemas}) do |
| 190 | + defp encode_schema(%Zoi.Types.Intersection{schemas: schemas} = schema) do |
| 160 191 | %{ |
| 161 192 | allOf: Enum.map(schemas, &encode_schema/1) |
| 162 193 | } |
| 194 | + |> encode_metadata(schema) |
| 163 195 | end |
| 164 196 | |
| 165 | - defp encode_schema(%Zoi.Types.Union{schemas: schemas}) do |
| 197 | + defp encode_schema(%Zoi.Types.Union{schemas: schemas} = schema) do |
| 166 198 | %{ |
| 167 199 | anyOf: Enum.map(schemas, &encode_schema/1) |
| 168 200 | } |
| 201 | + |> encode_metadata(schema) |
| 169 202 | end |
| 170 203 | |
| 171 | - defp encode_schema(%Zoi.Types.Date{}) do |
| 204 | + defp encode_schema(%Zoi.Types.Date{} = schema) do |
| 172 205 | %{type: :string, format: :date} |
| 206 | + |> encode_metadata(schema) |
| 173 207 | end |
| 174 208 | |
| 175 | - defp encode_schema(%Zoi.ISO.Date{}) do |
| 209 | + defp encode_schema(%Zoi.ISO.Date{} = schema) do |
| 176 210 | %{type: :string, format: :date} |
| 211 | + |> encode_metadata(schema) |
| 177 212 | end |
| 178 213 | |
| 179 | - defp encode_schema(%Zoi.Types.DateTime{}) do |
| 214 | + defp encode_schema(%Zoi.Types.DateTime{} = schema) do |
| 180 215 | %{type: :string, format: :"date-time"} |
| 216 | + |> encode_metadata(schema) |
| 181 217 | end |
| 182 218 | |
| 183 | - defp encode_schema(%Zoi.ISO.DateTime{}) do |
| 219 | + defp encode_schema(%Zoi.ISO.DateTime{} = schema) do |
| 184 220 | %{type: :string, format: :"date-time"} |
| 221 | + |> encode_metadata(schema) |
| 185 222 | end |
| 186 223 | |
| 187 | - defp encode_schema(%Zoi.Types.NaiveDateTime{}) do |
| 224 | + defp encode_schema(%Zoi.Types.NaiveDateTime{} = schema) do |
| 188 225 | %{type: :string, format: :"date-time"} |
| 226 | + |> encode_metadata(schema) |
| 189 227 | end |
| 190 228 | |
| 191 | - defp encode_schema(%Zoi.ISO.NaiveDateTime{}) do |
| 229 | + defp encode_schema(%Zoi.ISO.NaiveDateTime{} = schema) do |
| 192 230 | %{type: :string, format: :"date-time"} |
| 231 | + |> encode_metadata(schema) |
| 193 232 | end |
| 194 233 | |
| 195 | - defp encode_schema(%Zoi.Types.Time{}) do |
| 234 | + defp encode_schema(%Zoi.Types.Time{} = schema) do |
| 196 235 | %{type: :string, format: :time} |
| 236 | + |> encode_metadata(schema) |
| 197 237 | end |
| 198 238 | |
| 199 | - defp encode_schema(%Zoi.ISO.Time{}) do |
| 239 | + defp encode_schema(%Zoi.ISO.Time{} = schema) do |
| 200 240 | %{type: :string, format: :time} |
| 241 | + |> encode_metadata(schema) |
| 201 242 | end |
| 202 243 | |
| 203 244 | defp encode_schema(schema) do |
| @@ -337,4 +378,17 @@ defmodule Zoi.JSONSchema do | |
| 337 378 | # json_schema |
| 338 379 | end |
| 339 380 | end |
| 381 | + |
| 382 | + defp encode_metadata(json_schema, zoi_schema) do |
| 383 | + Enum.reduce(Zoi.metadata(zoi_schema), json_schema, fn |
| 384 | + {:description, description}, acc -> |
| 385 | + Map.put(acc, :description, description) |
| 386 | + |
| 387 | + {:example, example}, acc -> |
| 388 | + Map.put(acc, :example, example) |
| 389 | + |
| 390 | + _, acc -> |
| 391 | + acc |
| 392 | + end) |
| 393 | + end |
| 340 394 | end |
| @@ -2,7 +2,7 @@ defmodule Zoi.MixProject do | |
| 2 2 | use Mix.Project |
| 3 3 | |
| 4 4 | @source_url "https://github.com/phcurado/zoi" |
| 5 | - @version "0.7.0" |
| 5 | + @version "0.7.1" |
| 6 6 | |
| 7 7 | def project do |
| 8 8 | [ |
| @@ -65,11 +65,12 @@ defmodule Zoi.MixProject do | |
| 65 65 | |
| 66 66 | defp docs do |
| 67 67 | [ |
| 68 | - main: "Zoi", |
| 68 | + main: "readme", |
| 69 69 | source_ref: "v#{@version}", |
| 70 70 | logo: "guides/images/logo.png", |
| 71 71 | extra_section: "GUIDES", |
| 72 72 | source_url: @source_url, |
| 73 | + groups_for_extras: groups_for_extras(), |
| 73 74 | skip_undefined_reference_warnings_on: ["CHANGELOG.md"], |
| 74 75 | extras: extras() |
| 75 76 | ] |
| @@ -77,12 +78,19 @@ defmodule Zoi.MixProject do | |
| 77 78 | |
| 78 79 | defp extras do |
| 79 80 | [ |
| 80 | - "README.md", |
| 81 81 | "CHANGELOG.md", |
| 82 | - "guides/converting_keys_from_object.md", |
| 83 | - "guides/generating_schemas_from_json_example.md", |
| 82 | + "README.md", |
| 83 | + "guides/quickstart_guide.md", |
| 84 84 | "guides/using_zoi_to_generate_openapi_specs.md", |
| 85 | - "guides/validating_controller_parameters.md" |
| 85 | + "guides/validating_controller_parameters.md", |
| 86 | + "guides/converting_keys_from_object.md", |
| 87 | + "guides/generating_schemas_from_json_example.md" |
| 88 | + ] |
| 89 | + end |
| 90 | + |
| 91 | + defp groups_for_extras do |
| 92 | + [ |
| 93 | + Guides: ~r/guides\/.*\.md/ |
| 86 94 | ] |
| 87 95 | end |
| 88 96 | end |