phcurado

phcurado

Zoi - schema validation library inspired by Zod

Zoi is a new schema validation library for Elixir.

It’s inspired by Zod from the JavaScript ecosystem, bringing a similar functional API for defining, validating, transforming and coercing data, using elixir pipes for the schema definition.

Basic Example

iex> schema = Zoi.string() |> Zoi.min(3)
iex> Zoi.parse(schema, "hello")
{:ok, "hello"}
iex> Zoi.parse(schema, "hi")
{:error, [%Zoi.Error{message: "too small: must have at least 3 characters"}]}

Transformations

iex> schema = Zoi.string() |> Zoi.trim()
iex> Zoi.parse(schema, "    world    ")
{:ok, "world"}

Coercion

iex> Zoi.string() |> Zoi.parse(123)
{:error, [%Zoi.Error{message: "invalid type: must be a string"}]}
iex> Zoi.string(coerce: true) |> Zoi.parse(123)
{:ok, "123"}

Complex schemas

iex> user_schema =
...>   Zoi.object(%{
...>     name: Zoi.string() |> Zoi.min(2) |> Zoi.max(100),
...>     age: Zoi.integer() |> Zoi.min(18) |> Zoi.max(120),
...>     email: Zoi.email()
...>   })
iex> Zoi.parse(user_schema, %{name: "Alice", age: 30, email: "alice@email.com"})
{:ok, %{name: "Alice", age: 30, email: "alice@email.com"}}

There are many built in types, validations and transformations. Check out the documentation for all the possibilities.


:books: Docs: Zoi — Zoi v0.16.1
:package: Hex: zoi | Hex
:laptop: Repo:

I would love to hear your feedback, thoughts and any additional features you’d like to see

Most Liked

phcurado

phcurado

v0.10 released with Phoenix form support :rocket:

Hi everyone! I finally released the 0.10 version of Zoi, now you can use your Zoi schemas directly in Phoenix forms.
This release implements the Phoenix.HTML.FormData protocol, which allows you to use Zoi.Context structs as form data sources.

Quick example:

# Define schema inline
@user_schema Zoi.object(%{
  name: Zoi.string() |> Zoi.min(3),
  email: Zoi.email()
}) |> Zoi.Form.prepare()

# Parse and render (just like changesets!)
ctx = Zoi.Form.parse(@user_schema, params)
form = to_form(ctx, as: :user)

socket |> assign(:form, form)

# Use in your forms
~H"""
<.form for={@form} phx-submit="save">
  <.input field={@form[:name]} label="Name" />
  <.input field={@form[:email]} label="Email" />
  <div>
    <.button>Save</.button>
  </div>
</.form>
"""

Guides

Release v0.10: zoi | Hex

phcurado

phcurado

Zoi is reaching 10k downloads on hex.pm :star:

I would like to thank everyone who has used and supported this library. Every feedback has been taken seriously and helped to improve this project.

These are the main features that have been added based on feedback:

  • Zoi.describe/2: function for generating documentation based on descriptions your schema.
  • Zoi.Form: module that integrates with Phoenix forms.
  • Zoi.JSONSchema: Converting Zoi schemas to JSON Schema (for API documentation, validation, etc.).
  • Zoi.Struct: A helper module to define and validate structs using Zoi schemas
  • Zoi.Schema: Utilities for traversing and transforming Zoi schemas.

And many more added into the project’s internals!

I created a blog post where I walk through some of the Zoi features and the reason behind creating this library.

Check it out here.

Don’t forget to check the git repo and if you have any feedback or suggestions, feel free to open an issue or a PR.

phcurado

phcurado

New 0.15.0 release

Hi everyone!

This new version brings more types and more flexibility with elixir typespecs.

New typespec keyword:

Zoi.integer(gte: 0, typespec: quote(do: non_neg_integer()))
Zoi.any(typespec: quote(do: pos_integer()))

If you have a more complex schema which cannot be fully expressed by the Zoi inferred typespec, you can use this approach to express your type the way you want.

New types

  • Zoi.pid/1 type for validating pid values
  • Zoi.module/1 type for validating module values
  • Zoi.reference/1 type for validating reference values
  • Zoi.port/1 type for validating port values
  • Zoi.macro/1 type for validating quoted expressions (Macro.t())
  • Zoi.function/1 type for validating function values with optional arity constraint
  • Zoi.json/1 type for validating any JSON-compatible value (string, number, boolean, null, array, or object with string keys)

Zoi.map/2 is now preferred over Zoi.object/2

This was a feedback from @jam and I was slowly improving the map type to align more with the Elixir native map. Now you can express maps the same as we could express objects with some extras, examples:

# Map with string keys and values are integers
Zoi.map(Zoi.string(), Zoi.integer())

# Map with any key and values
Zoi.map()

# A map the follows a given structure (same as object):
Zoi.map(%{
  name: Zoi.string(),
  age: Zoi.integer() |> Zoi.optional()
})

no changes were made in Zoi.object/2, it uses a structured Zoi.map/2 under the hood and I don’t plan to deprecate this type.

Zoi is 43% faster when parsing

I decided to do some benchmarks and found some areas for improvements. Zoi is even faster when parsing deeply nested data structure. Now Zoi parses 43% faster compared to the previous implementation. You can run the benchmarks by following the documentation here.


:books: Docs: hexdocs.pm/zoi
:package: Hex: hex.pm/packages/zoi
:laptop: Repo: github.com/phcurado/zoi

Where Next?

Popular in Announcing Top

tmbb
I’ve published the first version of my Makeup library. It’s a syntax highlighter for Elixir in the spirit of Pygments, Currently it highl...
New
josevalim
Hi everyone, We would like to announce that Plataformatec is working on a new MySQL driver called MyXQL. Our goal is to eventually integ...
New
Crowdhailer
The latest release of Ace (0.10.0) includes serving content over HTTP/2. I have started writing a webserver to teach my self more about...
New
josevalim
EDIT: since Ecto 3.0 final version is out, this post was amended to use the final versions in the instructions below. Hi everyone, We a...
New
gabrielpoca
Hello everyone! I want to share with you something that I’m really proud of: https://stillstatic.io/ Still is a static site builder for...
New
bryanjos
Hi, I just published version 0.23.0 of Elixirscript. Most of the changes are around JavaScript interop now that Elixirscript uses the ...
New
Flo0807
Hello everyone! I am excited to share our heart project Backpex with you. After building several Phoenix applications, we realized that...
New
hpopp
After just over two years in development, this latest version of Pigeon is what I finally consider done in regards to my original vision ...
New
michalmuskala
Hello everybody. I have just released Jason - a new JSON library. You might be wondering, why do we need a new library? The primary foc...
New
benlime
LiveMotion enables high performance animations declared on the server and run on the client. As a follow up to my previous thread A libr...
New

Other popular topics Top

chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39247 209
New
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 47849 226
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
hariharasudhan94
Lets say i have map like this fetching from my database %{"_id" =&gt; #BSON.ObjectId&lt;58eb1a7a9ad169198c3dXXXX&gt;, "email" =&gt; "XX...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

We're in Beta

About us Mission Statement