如何将params前端与后端API

时间:2017-05-11 01:56:44

标签: javascript reactjs elixir phoenix-framework

我目前正在使用Elixir编写的phx API,我可以使用Postman成功创建一个帐户。但是,当我尝试使用React.js前端创建一个帐户时,我在控制台中获得了以下堆栈跟踪。

[debug] Simple CORS request from Origin 'http://localhost:3000' is allowed
[debug] Processing with KegCopRAPI.Web.UserController.create/2
  Parameters: %{"email" => "diana@example.com", "password" => "[FILTERED]", "username" => "diana"}
  Pipelines: [:api]
[info] Sent 400 in 1ms
[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" => "diana@example.com", "password" => "password", "username" => "diana"}

    (kegcopr_api) lib/kegcopr_api/web/controllers/user_controller.ex:17: 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" => "diana@example.com", "password" => "password", "username" => "diana"}, cookies: %Plug.Conn.Unfetched{aspect: :cookies}, halted: false, host: "localhost", method: "POST", owner: #PID<0.413.0>, params: %{"email" => "diana@example.com", "password" => "password", "username" => "diana"}, path_info: ["api", "users"], path_params: %{}, peer: {{127, 0, 0, 1}, 58421}, port: 4000, private: %{KegCopRAPI.Web.Router => {[], %{}}, :guardian_default_claims => {:error, %CaseClauseError{term: {:error, {:badarg, ["null"]}}}}, :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: [{"host", "localhost:4000"}, {"connection", "keep-alive"}, {"content-length", "70"}, {"accept", "application/json"}, {"origin", "http://localhost:3000"}, {"user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36"}, {"authorization", "Bearer: null"}, {"content-type", "application/json"}, {"referer", "http://localhost:3000/signup"}, {"accept-encoding", "gzip, deflate, br"}, {"accept-language", "en-US,en;q=0.8"}], request_path: "/api/users", resp_body: nil, resp_cookies: %{}, resp_headers: [{"cache-control", "max-age=0, private, must-revalidate"}, {"x-request-id", "ka5l96ctaijuthp39krkbg597n4r75lj"}, {"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" => "diana@example.com", "password" => "password", "username" => "diana"})
    (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

我注意到我需要更改React.js前端的输入值以匹配API的已接受参数。

可以找到前端here。我相信需要更新的文件是 src / components / Input / index.js ,但我知道这是错误的。

    // @flow
    import React from 'react';

    type Props = {
      input: Object,
      label?: string,
      type?: string,
      placeholder?: string,
      style?: Object,
      meta: Object,
    }

    const Input = ({ input, label, type, placeholder, style, meta }: Props) =>
      <div style={{ marginBottom: '1rem' }}>
        {label && <label htmlFor={input.name}>{label}</label>}
        <input
          {...input}
          type={type}
          placeholder={placeholder}
          className="form-control"
          style={style && style}
        />
        {meta.touched && meta.error &&
          <div style={{ fontSize: '85%', color: 'rgb(255,59,48)' }}>{meta.error}</div>
        }
      </div>;

export default Input;

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

非常感谢任何和所有帮助。

1 个答案:

答案 0 :(得分:1)

您从React发送顶级表单的字段,但在后端控制器中,您从"user"键内部获取数据。您需要将React发送的数据放在user密钥下。在:

export function signup(data, router) {
  return dispatch => api.post('/users', data)
    .then((response) => {
      setCurrentUser(dispatch, response);
      dispatch(reset('signup'));
      router.transitionTo('/');
    });
}

变化:

api.post('/users', data)

为:

api.post('/users', { user: data })

我发现您在其他一些功能中也会发送这样的数据,您需要根据接受后端数据的方式相应地调整它们。