Reputation: 490
I am working with simple phoenix elixir application. In this app I'm trying to expose a rest api to save and retrieve data.
In my case, if the primary key (email address ) is a duplicate, my application throws an error. I need to know the best way to handle this error; either try-catch or any other better solutions.
this is my data save method
def post(conn, %{"stooge" => stooge, "name" => name, "email" => email , "password" => password})do
respond = Repo.insert!(%ApiDb.User{name: name, email: email, stooge: stooge, password: password})
json conn, respond
end
sample payload
{
"stooge": "moe",
"name": "Joe",
"email": "[email protected]",
"password":"asdasd"
}
models/user.ex
defmodule ApiDb.User do
use ApiDb.Web, :model
schema "users" do
field :password, :string
field :name, :string
field :email, :string
field :stooge, :string
timestamps()
end
@doc """
Builds a changeset based on the `struct` and `params`.
"""
def changeset(struct, params \\ %{}) do
struct
|> cast(params, [:name, :email, :password, :stooge])
|> validate_required([:name, :email, :password])
|> validate_format(:email, ~r/@/)
end
end
I tried the try-catch blocks but there was no luck
try do
respond = Repo.insert!(%ApiDb.User{name: name, email: email, stooge: stooge, password: password})
json conn, respond
rescue
e in Ecto.ConstraintError -> IO.puts("An error occurred: ")
end
Upvotes: 2
Views: 5057
Reputation: 371
After Phoenix 1.3 release there is another way: to user action_fallback
Here is an example from the docs
defmodule MyController do
use Phoenix.Controller
action_fallback MyFallbackController
def show(conn, %{"id" => id}, current_user) do
with {:ok, post} <- Blog.fetch_post(id),
:ok <- Authorizer.authorize(current_user, :view, post) do
render(conn, "show.json", post: post)
end
end
end
It allows to move error handling to fallback controller and reuse it across the app:
defmodule MyFallbackController do
use Phoenix.Controller
def call(conn, {:error, :not_found}) do
conn
|> put_status(:not_found)
|> render(MyErrorView, :"404")
end
def call(conn, {:error, :unauthorized}) do
conn
|> put_status(403)
|> render(MyErrorView, :"403")
end
end
Upvotes: 3
Reputation: 490
found nice and easy way to do that
def post(conn, %{"stooge" => stooge, "name" => name, "email" => email , "password" => password})do
try do
respond = Repo.insert!(%ApiDb.User{name: name, email: email, stooge: stooge, password: password})
json conn, respond
rescue
e in Ecto.ConstraintError -> json conn, (%{"status" => false, "message" => e.message})
end
end
Upvotes: 0
Reputation: 4527
Call the ApiDbUser.changeset function, then call Repo.insert with the changeset. It will return tuple with either :ok, or :error
def post(conn, params) do
changeset = ApiDb.User.changeset(%ApiDb.User{}, params)
case Repo.insert(changeset) do
{:ok, user} ->
# create a render("user.json", params) function in your UserView
render conn, "user.json", user: user
{:error, changeset}
# create a render("error.json", params) function in your UserView
render conn, "error.json", changeset: changeset
end
end
Upvotes: 5