【问题标题】:What is the best way of error handling in elixirElixir中错误处理的最佳方法是什么
【发布时间】:2017-11-13 16:28:55
【问题描述】:

我正在使用简单的 phoenix elixir 应用程序。在这个应用程序中,我试图公开一个 rest api 来保存和检索数据。

就我而言,如果主键(电子邮件地址)重复,我的应用程序会抛出错误。 我需要知道处理此错误的最佳方法; try-catch 或任何其他更好的解决方案。

这是我的数据保存方法

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

样本负载

{
    "stooge": "moe",
    "name": "Joe",
    "email": "p31111ww11eee32111111134@dmain.com",
    "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

错误

我尝试了 try-catch 块,但没有运气

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

【问题讨论】:

  • 您应该在ApiDb.User 中创建一个changeset 函数,按照错误消息的说明将unique_constraint 添加到其中,然后在控制器中使用Repo.insertcase 来处理错误案子。尝试在全新的应用程序中使用phoenix.gen.json 生成模型并研究其来源或阅读phoenixframework.org/docs/ecto-models(尤其是该页面上的case Repo.insert(changeset) do ...)。
  • 我有这个模型 defmodule ApiDb.User 使用 ApiDb.Web,:model schema "users" do field :password, :string field :name, :string field :email, :string field :stooge , :string timestamps() end end
  • @Dogbert 你能用我的应用举例指导我吗

标签: elixir phoenix-framework


【解决方案1】:

调用 ApiDbUser.changeset 函数,然后使用变更集调用 Repo.insert。它将返回带有 :ok 或 :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

【讨论】:

  • 我的案例 phoenix 作为 api 而不是前端。顺便说一句,回复很好
  • 我提供的答案是针对 API,而不是前端。如果您在视图中实现def render("user.json", %{user: user}), do: user 函数,phoenix 将自动对您的 JSON 响应进行编码。
【解决方案2】:

Phoenix 1.3 发布后还有另一种方式:致用户action_fallback 这是来自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

它允许将错误处理移动到回退控制器并在整个应用程序中重复使用:

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

【讨论】:

    【解决方案3】:

    找到了很好且简单的方法

     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
    

    【讨论】:

    • 它适用于几种情况,但是如果您必须为每个控制器中的每个操作都执行此操作,它会变得很烦人并且您最终会得到丑陋的代码。它根本不干。异常可以“冒泡”吗?
    猜你喜欢
    • 1970-01-01
    • 2015-06-12
    • 2017-12-26
    • 1970-01-01
    • 2020-06-18
    • 1970-01-01
    • 2016-03-27
    • 1970-01-01
    • 2010-09-06
    相关资源
    最近更新 更多