Following up on the discussion here. I have started working on Zoi.Ecto integration.
The idea is to define the schema with Zoi and derive an Ecto embedded schema from it, so Zoi remains the source schema for validation, coercion and Ecto provides the struct and changeset interface.
The API looks like this:
defmodule MyApp.User do
require Zoi.Ecto
@schema Zoi.map(%{
email: Zoi.email(),
name: Zoi.string(),
address:
Zoi.map(%{
street: Zoi.string(),
number: Zoi.integer()
})
})
Zoi.Ecto.generate_embedded_schema(@schema)
end
This generates the embedded_schema from the Zoi schema, I’m mapping Zoi types to ecto, including embeds_one and embeds_many from Zoi map/lists. Unsuported types for now I’m defaulting to :map.
For example using the Zoi changeset function, zoi parses it and encapsulate to a changeset struct:
iex> Zoi.Ecto.changeset(%MyApp.User{}, %{email: "invalid", address: %{street: "street"}})
#Ecto.Changeset<
changes: %{
address: #Ecto.Changeset<
changes: %{street: "street"},
errors: [number: {"is required", [code: :required]}],
valid?: false
>,
email: "invalid"
},
errors: [email: {"invalid email format", [code: :invalid_format]}],
valid?: false
>
You can track the issue here:
- Issue: Zoi + Ecto and Changesets · Issue #158 · phcurado/zoi · GitHub
- Draft PR: add integration with ecto embedded schemas and changeset by phcurado · Pull Request #159 · phcurado/zoi · GitHub
If you are interested in this integration, feel free to jump in. It’s still an early implementation so feel free to give feedback and suggestions. If you have a codebase you want to validate even better, I can change/adapt things on the code as need it. It can be extended to generate ecto schemas (not only embeds) if people are interested in that but first good to validate this simpler use case.






















