vt-elixir / ja_serializer

JSONAPI.org Serialization in Elixir.
Other
640 stars 148 forks source link

Using JaSerializer.PhoenixView results in no function clause matching in Plug.Conn.resp/3 #328

Closed mick-h closed 5 years ago

mick-h commented 5 years ago

Hi there,

I'm trying to use JaSerializer 0.15.0 with Phoenix 1.4.9. I've added: use JaSerializer.PhoenixView to the view module, then changed the render call to: render(conn, "show.json-api", data: %{id: 1, name: "Joe", age: 43}) but when I hit the url I get the mentioned error:

Request: GET /api/users/1
** (exit) an exception was raised:
    ** (FunctionClauseError) no function clause matching in Plug.Conn.resp/3
        (plug) lib/plug/conn.ex:577: Plug.Conn.resp(%Plug.Conn{adapter: {Plug.Cowboy.Conn, :...}, assigns: %{data: %{age: 43, id: 1, name: "Joe"}, layout: false}, before_send: [#Function<0.23780992/1 in Plug.Telemetry.call/2>], body_params: %{}, cookies: %Plug.Conn.Unfetched{aspect: :cookies}, halted: false, host: "localhost", method: "GET", owner: #PID<0.464.0>, params: %{"id" => "1"}, path_info: ["api", "users", "1"], path_params: %{"id" => "1"}, port: 4000, private: %{JsonApiWeb.Router => {[], %{}}, :phoenix_action => :show, :phoenix_controller => JsonApiWeb.UserController, :phoenix_endpoint => JsonApiWeb.Endpoint, :phoenix_format => "json", :phoenix_layout => {JsonApiWeb.LayoutView, :app}, :phoenix_router => JsonApiWeb.Router, :phoenix_template => "show.json-api", :phoenix_view => JsonApiWeb.UserView, :plug_session_fetch => #Function<1.64872641/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: [{"accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3"}, {"accept-encoding", "gzip, deflate, br"}, {"accept-language", "en-US,en;q=0.9"}, {"cache-control", "max-age=0"}, {"connection", "keep-alive"}, {"host", "localhost:4000"}, {"referer", "http://localhost:4000/api/users/1"}, {"upgrade-insecure-requests", "1"}, {"user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"}], request_path: "/api/users/1", resp_body: nil, resp_cookies: %{}, resp_headers: [{"content-type", "application/vnd.api+json; charset=utf-8"}, {"cache-control", "max-age=0, private, must-revalidate"}, {"x-request-id", "FbB_zZIr8nixPW8AAAAD"}], scheme: :http, script_name: [], secret_key_base: :..., state: :unset, status: nil}, 200, %{"data" => %{"attributes" => %{"age" => 43, "name" => "Joe"}, "id" => "1", "type" => "user"}, "jsonapi" => %{"version" => "1.0"}})
        (phoenix) lib/phoenix/controller.ex:746: Phoenix.Controller.instrument_render_and_send/4
        (json_api) lib/json_api_web/controllers/user_controller.ex:25: JsonApiWeb.UserController.show/2
        (json_api) lib/json_api_web/controllers/user_controller.ex:1: JsonApiWeb.UserController.action/2
        (json_api) lib/json_api_web/controllers/user_controller.ex:1: JsonApiWeb.UserController.phoenix_controller_pipeline/2
        (phoenix) lib/phoenix/router.ex:288: Phoenix.Router.__call__/2
        (json_api) lib/json_api_web/endpoint.ex:1: JsonApiWeb.Endpoint.plug_builder_call/2
        (json_api) lib/plug/debugger.ex:122: JsonApiWeb.Endpoint."call (overridable 3)"/2
        (json_api) lib/json_api_web/endpoint.ex:1: JsonApiWeb.Endpoint.call/2
        (phoenix) lib/phoenix/endpoint/cowboy2_handler.ex:40: Phoenix.Endpoint.Cowboy2Handler.init/2
        (cowboy) /Users/mick/dev/code/json_api/deps/cowboy/src/cowboy_handler.erl:41: :cowboy_handler.execute/2
        (cowboy) /Users/mick/dev/code/json_api/deps/cowboy/src/cowboy_stream_h.erl:296: :cowboy_stream_h.execute/3
        (cowboy) /Users/mick/dev/code/json_api/deps/cowboy/src/cowboy_stream_h.erl:274: :cowboy_stream_h.request_process/3
        (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3

I can see that the render function in JaSerializer.PhoenixView gets called and returns %{"data" => %{"attributes" => %{"age" => 43, "name" => "Mick"}, "id" => "1", "type" => "user"}, "jsonapi" => %{"version" => "1.0"}} which looks fine, but it then seems to go astray in the controller code.

Am I doing something wrong here? Any help much appreciated.

Mick

beerlington commented 5 years ago

It looks like something is up with the request. I would expect to see "json-api" as the phoenix_format under the private key and "application/vnd.api+json" in the request's accept key. Have you verified that everything is correct in the configuration? https://github.com/vt-elixir/ja_serializer#configuration

mick-h commented 5 years ago

That was it. Though interestingly, the format encoder config specified in the README:

config :phoenix, :format_encoders,
  "json-api": Poison

did not work, because Poison does not have a encode_to_iodata! function. Jason does, so when I changed it to:

config :phoenix, :format_encoders,
  "json-api": Jason

it worked fine.

Thanks for the fast response!