Hello everyone,
I’m actually studying elixir and phoenix, I’m testing phoenix
I’m learning how to create a rest API JSON
I’m trying to get users and show it as JSON but when try to use json(conn, users)
I get this error
protocol Jason.Encoder not implemented for %Test.Accounts.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">, id: 3, email: "test@hotmail.com", encrypted_password: "qowejoqiwjeo", valid: true, password: nil, password_confirmation: nil, created_at: ~N[2023-10-05 20:00:46], updated_at: ~N[2023-10-05 20:00:46]} of type Test.Accounts.User (a struct), Jason.Encoder protocol must always be explicitly implemented.
Here is my controller
defmodule TestWeb.TestController do
use TestWeb, :controller
alias Test.Contexts.Users
def test1(conn, _params) do
users = Users.list_users() |> IO.inspect(label: "testcontroller")
json(conn, users)
end
end
The output of IO.inspect
testcontroller: [
%Test.Accounts.User{
__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
id: 3,
email: "test@hotmail.com",
encrypted_password: "qowejoqiwjeo",
valid: true,
password: nil,
password_confirmation: nil,
created_at: ~N[2023-10-05 20:00:46],
updated_at: ~N[2023-10-05 20:00:46]
}
]
I discover that if I delete some elements from the struct
defmodule TestWeb.TestController do
use TestWeb, :controller
alias Test.Contexts.Users
def test1(conn, _params) do
users = Users.list_users() |> IO.inspect(label: "testcontroller")
# This way
# users = users |> Enum.map(&(Map.delete(&1, :__meta__) |> Map.from_struct()))
# or this way
users = users |> Enum.map(&Map.drop(&1, [:__meta__, :__struct__]))
json(conn, users)
end
end
I got the result in explorer
[{"id":3,"valid":true,"password":null,"email":"test@hotmail.com","password_confirmation":null,"created_at":"2023-10-05T20:00:46","encrypted_password":"123123","updated_at":"2023-10-05T20:00:46"},{"id":4,"valid":false,"password":null,"email":"test@gmail.com","password_confirmation":null,"created_at":"2023-10-05T20:39:23","encrypted_password":"123123123","updated_at":"2023-10-05T20:39:23"}]
My questions are the next
- I don’t know if I’m doing it correctly, but this is the right way?
- I need always to delete
:__meta__
and:__struct__
and others elements to work correctly? - I discovery that you can create a module to have the bodies format o similar to this:
defmodule TestWeb.TestJSON do
def all(%{users: users}) do
for(user <- users, do: data(user)
end
defp data(%User{} = user) do
%{
id: user.id,
emai: user.email,
valido: user.valid,
creado: user.created_at,
modificado: user.updated_at
}
end
end
# And use in the controller like this...
defmodule TestWeb.TestController do
use TestWeb, :controller
alias Test.Contexts.Users
def test1(conn, _params) do
users = Users.list_users()
render(conn, :all, users: users)
end
end
- Another question, is there a way to render, sending all users like this
render(conn, :all, users)
and receive like thisdef all(users) do
?