【问题标题】:How to properly send JSON data to a phx phoenix API如何正确地将 JSON 数据发送到 phx phoenix API
【发布时间】:2017-10-05 18:22:02
【问题描述】:

我正在使用 Elixir 编写 Phoenix / phx API,并且我正在尝试使用 Postman 测试 JSON API 的功能。我正在向 API 发送 JSON 数据,希望能创建一个新用户,但 phx 给了我以下错误。

Phoenix.ActionClauseError at POST /api/users

不确定问题到底出在哪里,所以我将发布 phx 项目的路由器和控制器。

router.ex

defmodule KegCopRAPI.Web.Router do
  use KegCopRAPI.Web, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
    plug Guardian.Plug.VerifyHeader, realm: "Bearer"
    plug Guardian.Plug.LoadResource
  end

  scope "/", KegCopRAPI.Web do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
  end

  # Other scopes may use custom stacks.
  scope "/api", KegCopRAPI.Web do
    pipe_through :api

    post "/sessions", SessionController, :create
    delete "/sessions", SessionController, :delete
    post "/sessions/refresh", SessionController, :refresh

    resources "/users", UserController, except: [:show, :index, :new, :edit]
  end
end

user_controller.ex

  def create(conn, %{"user" => user_params}) do
    # with {:ok, %User{} = user} <- Accounts.create_user(user_params) do
    changeset = User.registration_changeset(%User{}, user_params)

    case Repo.insert(changeset) do
      {:ok, user} ->
        new_conn = Guardian.Plug.api_sign_in(conn, user, :access)
        jwt = Guardian.Plug.current_token(new_conn)
        # conn
        # |> put_status(:created)
        # |> put_resp_header("location", user_path(conn, :show, user))
        # |> render("show.json", user: user)
        new_conn
        |> put_status(:created)
        |> render(KegCopRAPI.SessionView, "show.json", user: user, jwt: jwt)
      {:error, changeset} ->
        conn
        |> put_status(:unprocessable_entity)
        |> render(KegCopRAPI.ChangesetView, "error.json", changeset: changeset)
    end
  end

整个项目可以找到here 任何和所有的帮助将不胜感激。

我正在使用以下 Postman 设置向 API 发送数据,

下面的完整错误信息,

[info] POST /api/users
[debug] Processing with KegCopRAPI.Web.UserController.create/2
  Parameters: %{"email" => "foo@example.com", "password" => "[FILTERED]", "username" => "foo"}
  Pipelines: [:api]
[info] Sent 400 in 10ms
[debug] ** (Phoenix.ActionClauseError) could not find a matching KegCopRAPI.Web.UserController.create clause
to process request. This typically happens when there is a
parameter mismatch but may also happen when any of the other
action arguments do not match. The request parameters are:

  %{"email" => "foo@example.com", "password" => "password", "username" => "foo"}

    (kegcopr_api) lib/kegcopr_api/web/controllers/user_controller.ex:14: KegCopRAPI.Web.UserController.create(%Plug.Conn{adapter: {Plug.Adapters.Cowboy.Conn, :...}, assigns: %{}, before_send: [#Function<1.33581574/1 in Plug.Logger.call/2>, #Function<0.72433304/1 in Phoenix.LiveReloader.before_send_inject_reloader/2>], body_params: %{"email" => "foo@example.com", "password" => "password", "username" => "foo"}, cookies: %Plug.Conn.Unfetched{aspect: :cookies}, halted: false, host: "localhost", method: "POST", owner: #PID<0.2357.0>, params: %{"email" => "foo@example.com", "password" => "password", "username" => "foo"}, path_info: ["api", "users"], path_params: %{}, peer: {{127, 0, 0, 1}, 59852}, port: 4000, private: %{KegCopRAPI.Web.Router => {[], %{}}, :guardian_default_resource => nil, :phoenix_action => :create, :phoenix_controller => KegCopRAPI.Web.UserController, :phoenix_endpoint => KegCopRAPI.Web.Endpoint, :phoenix_format => "json", :phoenix_layout => {KegCopRAPI.Web.LayoutView, :app}, :phoenix_pipelines => [:api], :phoenix_router => KegCopRAPI.Web.Router, :phoenix_view => KegCopRAPI.Web.UserView, :plug_session_fetch => #Function<1.131660147/1 in Plug.Session.fetch_session/1>}, query_params: %{}, query_string: "", remote_ip: {127, 0, 0, 1}, req_cookies: %Plug.Conn.Unfetched{aspect: :cookies}, req_headers: [{"cache-control", "no-cache"}, {"postman-token", "da608739-758b-40d7-bdef-23b3c2a63bed"}, {"content-type", "application/json"}, {"user-agent", "PostmanRuntime/3.0.11-hotfix.2"}, {"accept", "*/*"}, {"host", "localhost:4000"}, {"accept-encoding", "gzip, deflate"}, {"content-length", "76"}, {"connection", "keep-alive"}], request_path: "/api/users", resp_body: nil, resp_cookies: %{}, resp_headers: [{"cache-control", "max-age=0, private, must-revalidate"}, {"x-request-id", "slfdhshckenp3dinlqr22m5nlakhoaq4"}, {"access-control-allow-origin", "*"}, {"access-control-expose-headers", ""}, {"access-control-allow-credentials", "true"}, {"vary", ""}], scheme: :http, script_name: [], secret_key_base: "fIEpvi5ujSQEKgmkRpt83KiLPq068sSmvFKlWFZyNpi3nkNmUtYO24Em6cXIUblZ", state: :unset, status: nil}, %{"email" => "foo@example.com", "password" => "password", "username" => "foo"})
    (kegcopr_api) lib/kegcopr_api/web/controllers/user_controller.ex:1: KegCopRAPI.Web.UserController.action/2
    (kegcopr_api) lib/kegcopr_api/web/controllers/user_controller.ex:1: KegCopRAPI.Web.UserController.phoenix_controller_pipeline/2
    (kegcopr_api) lib/kegcopr_api/web/endpoint.ex:1: KegCopRAPI.Web.Endpoint.instrument/4
    (phoenix) lib/phoenix/router.ex:277: Phoenix.Router.__call__/1
    (kegcopr_api) lib/kegcopr_api/web/endpoint.ex:1: KegCopRAPI.Web.Endpoint.plug_builder_call/2
    (kegcopr_api) lib/plug/debugger.ex:123: KegCopRAPI.Web.Endpoint."call (overridable 3)"/2
    (kegcopr_api) lib/kegcopr_api/web/endpoint.ex:1: KegCopRAPI.Web.Endpoint.call/2
    (plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
    (cowboy) /opt/elixir/kegcopr_api/deps/cowboy/src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4

【问题讨论】:

  • 你能发布完整的错误信息吗?另外,您在 Postman 请求中是否有 Content-Type 等?
  • 好的,请稍等。我将内容类型设置为 JSON (application/json)
  • 你的数据应该是这样的:{"user": { "username": ..., ... } }.

标签: json elixir phoenix-framework


【解决方案1】:

由于您在 "user" 键内使用地图中的数据,因此您需要将所有字段放在请求中的 "user" 键下,如下所示:

{
  "user": {
    "username": "foo",
    "email": "foo@example.com",
    "password": "password"
  }
}

【讨论】:

    【解决方案2】:

    在你的控制器中你是模式匹配的

    "user" => user_params 
    

    因此,您必须将用户参数放在用户键下:

    "user": {
        "email": "foo@bar.com",
        ...
    }
    

    【讨论】:

      猜你喜欢
      • 2020-02-22
      • 1970-01-01
      • 2017-07-22
      • 1970-01-01
      • 2013-07-19
      • 1970-01-01
      • 1970-01-01
      • 2017-01-11
      • 1970-01-01
      相关资源
      最近更新 更多