I want to use Ash as the backend and Inertia.js as web ui. has anyone done this before? Any suggestions are welcome.
Cheers,
Zhen Zhang
I want to use Ash as the backend and Inertia.js as web ui. has anyone done this before? Any suggestions are welcome.
Cheers,
Zhen Zhang
Looking through the Phoenix docs it seems like what all you’d do differently is call into Ash instead of Ecto, and would need an adapter for representing errors. Not sure if they have a behavior or protocol you can implement, but it would be pretty easy to write something if they do.
inertia-phoenix doesn’t have such a behavior or protocol. assign_errors() calls compile_errors!() which converts the changeset errors into a shape inertia recognizes.
BTW, they require that schemas be serialized to json via @derive Jason.Encoder. what does Ash do for this?
Ash does not define a JSON serializer like that automatically, primarily because it doesn’t really make a lot of sense to do given that different things can be loaded in different cases etc. However, if you must go that approach, you can derive a serializer if you like or use a tool like ash_json to derive one for you.
It is problematic that Inertia-phoenix integrates directly with Ecto in my opinion instead of providing behaviors that would let it work with anything. Likely integrating Ash with intertia-phoenix would necessitate making improvements to inertia-phoenix.
Wish I had a better answer for you Ultimately, this is the fundamental flaw that arises when libraries use
Ecto.Schema
as the integration point, instead of defining a behavior or protocol and making an Ecto.Schema
implementation for it.
Hey Zach, i’m reviving this thread cause i got curious with something, inertia assign_errors
also accepts an elixir map, i took this map example from their docs
%{
"name" => "Name is required",
"password" => "Password must be at least 5 characters",
"team.name" => "Team name is required",
}
Would be possible to turn Ash.Changeset into a map with these structure ? If so, we could adapt ash with inertia
You can grab the errors, use Ash.Error.to_error_class
to aggregate them, get class.errors
which is a list group them by their field
and path
keys as a string, yes
Is there a way to retrieve validation error messages, such as those generated by allow_nil? false
and Ash.create!
, and incorporate them into a map? I’m looking for functionality similar to what happens when you submit an AshPhoenix.Form
and it’s validated, resulting in a set of error messages. How can I achieve something like this? There’s a try/rescue example in the docs but i was looking forward to something more elegant than that.
That’s what I was describing above. You can call Ash.Error.to_error_class
on the errors in a changeset or on a raised error and group up the errors that are in the errors
key.
My suggestion would be to actually leverage AshPhoenix.FormData.ToError
to extract errors that have known-to-be-safe messages.
error_or_errors
|> Ash.Error.to_error_class()
|> Map.get(:errors)
|> Enum.flat_map(fn error ->
if AshPhoenix.FormData.ToError.impl_for(error) do
error
|> AshPhoenix.FormData.ToError()
|> List.wrap()
|> Enum.map(fn {field, message, vars} ->
{Enum.join(error.path ++ [field], "."), replace_vars(message, vars)}
end)
else
[]
end
end)
defp replace_vars(message, vars) do
Enum.reduce(vars || [], message, fn {key, value}, acc ->
String.replace(acc, "%{#{key}}", to_string(value))
end)
end
This module really exists?
Sorry it’s just .Error
not .ToError
AshPhoenix.FormData.Error — ash_phoenix v2.1.18
I too am interested in using ash with react via Inertia. I opened a discussion regarding this on Gh to learn more about it. Got a great response but also realized my current Ash knowledge is not a a level where I could meaningfully contribute to it.
I’ll just link it here and hope to follow the progress of it, hope it be positive for both Ash and Inertia phoenix.
Just wanted to chime in to point out that inertia-phoenix has been updated to provide a protocol for dealing with errors: Inertia.Errors — Inertia v2.3.0
Should allow for translating back and forth between Ash and Inertia. I haven’t played with it yet so I can’t give an example but wanted to make sure people knew it was available.
That’s great! I think we can make inertia an optional dependency of ash_phoenix
in that case and implement the protocol there. Users should then be able to just drop an Ash.Changeset
, Ash.Query
, or Ash.ActionInput
in. I don’t have time to PR it but it would be a welcome addition!
@mbuhot is giving a talk about Inertia.js at Elixir Sidney this week. It’s online, so if the timezone isn’t a problem, you should check it out. Elixir Sydney - March 2025 edition · Zoom · Luma
@mbuhot is giving a talk about Inertia.js at Elixir Sidney this week.
Youtube link for the meetup talk: https://www.youtube.com/watch?v=PEtGNztJaHg
I’ve been experimenting with InertiaJS and Phoenix for an implementation of the RealWorld Demo app.
GitHub - team-alembic/realworld-phoenix-inertia-react (sorry for lack of docs!)
Overall it feels very simple, like good old MVC, but with React as your UI layer.
Having the page props immediately available so you never have loading states or error states from API requests is so nice.
The useForm
hook is excellent, you submit your form data and let the server either respond with errors or redirect to a new page showing the result.
The backend is using Ash, so I followed @zachdaniel’s suggestion to implement the Inertia.Errors
protocol which handles mapping errors from the domain layer onto form field errors.
The only issue I’ve run into was due to the way Inertia handles history navigation. By default it re-renders the page using the props originally provided when page was first loaded. In my case it caused inconsistency because parts of the page that would update in realtime by listening on a Phoenix Channel, but Inertia was unaware of those changes. I solved the problem by sending fresh state to the client after the Phoenix Channel joins.
To make it really nice I’d like to generate TypeScript types (maybe Zod schemas?) for any complex data types being rendered as props or sent over Phoenix Channels.
@mbuhot Thanks for the excellent talk! The repo you shared also helps answer a bunch of questions I had regarding simple things like flash messages and form handling. It’s going to save me a bunch of time trying to figure that stuff out on my own.