From an elixir genserver process I am executing the post_metdata method to send a JSON HTTP Patch request to a Phoenix endpoint (on another server). The server continues to error indicating no matching clause showing the JSON link structure is not being included in the params based to the method. The id is included but not the passed data payload. Any suggestions on what appears to be the problem?
Client code
defp post_metadata(metadata, webhook) do
case HTTPoison.patch webhook, encode(metadata), [{"content-type", "application/json"}] do
{:ok, %HTTPoison.Response{status_code: 200} = response} ->
# Logger.debug response.body
Logger.debug "Successfully extracted and posted metadata for #{webhook}"
{:error, %HTTPoison.Error{reason: reason}} ->
Logger.warn "Unable to extract and post metadata for #{webhook}"
end
end
defp encode(metadata) do
%{
"link":
%{
"title": metadata.title,
"description": metadata.description
}
}
|> Poison.encode!
end
Phoenix Controller method expected, but not being matched
def update(conn, %{"id" => id, "link" => link_params}) do
link = Repo.get!(Link, id)
changeset = Link.changeset(link, link_params)
case Repo.update(changeset) do
{:ok, link} ->
render(conn, "show.json", link: link)
{:error, changeset} ->
conn
|> put_status(:unprocessable_entity)
|> render(Mini.ChangesetView, "error.json", changeset: changeset)
end
end
router.ex
defmodule Mini.Router do
use Mini.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 Plug.Logger, log: :debug
end
scope "/", Mini do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
end
scope "/api", Mini do
pipe_through :api
resources "/links", LinkController, except: [:new, :edit]
end
end
Error logged to the console
[debug] ** (Phoenix.ActionClauseError) bad request to Mini.LinkController.update, no matching action clause to process request
(mini) web/controllers/link_controller.ex:39: Mini.LinkController.update(%Plug.Conn{adapter: {Plug.Adapters.Cowboy.Conn, :...}, assigns: %{}, before_send: [#Function<1.42492691/1 in Plug.Logger.call/2>, #Function<1.42492691/1 in Plug.Logger.call/2>, #Function<0.111727833/1 in Phoenix.LiveReloader.before_send_inject_reloader/2>], body_params: %{}, cookies: %Plug.Conn.Unfetched{aspect: :cookies}, halted: false, host: "localhost", method: "PATCH", owner: #PID<0.438.0>, params: %{"id" => "12"}, path_info: ["api", "links", "12"], path_params: %{}, peer: {{127, 0, 0, 1}, 55369}, port: 4000, private: %{Mini.Router => {[], %{}}, :phoenix_action => :update, :phoenix_controller => Mini.LinkController, :phoenix_endpoint => Mini.Endpoint, :phoenix_format => "json", :phoenix_layout => {Mini.LayoutView, :app}, :phoenix_pipelines => [:api], :phoenix_route => #Function<4.107513407/1 in Mini.Router.match_route/4>, :phoenix_router => Mini.Router, :phoenix_view => Mini.LinkView, :plug_session_fetch => #Function<1.61377594/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: [{"content-type", "application/json, application/json"}, {"user-agent", "hackney/1.6.6"}, {"host", "localhost:4000"}, {"content-length", "58"}], request_path: "/api/links/12", resp_body: nil, resp_cookies: %{}, resp_headers: [{"cache-control", "max-age=0, private, must-revalidate"}, {"x-request-id", "5bggaasurlj1oe027nvmv5aiek0hq3k8"}], scheme: :http, script_name: [], secret_key_base: "YfnqjmBhsSJMF/TmhK6qpMnJl7mS0tIYHk1tZ/dZUA6d7KOdv2g/AOJUfWo8sulb", state: :unset, status: nil}, %{"id" => "12"})
(mini) web/controllers/link_controller.ex:1: Mini.LinkController.action/2
(mini) web/controllers/link_controller.ex:1: Mini.LinkController.phoenix_controller_pipeline/2
(mini) lib/mini/endpoint.ex:1: Mini.Endpoint.instrument/4
(mini) lib/phoenix/router.ex:261: Mini.Router.dispatch/2
(mini) web/router.ex:1: Mini.Router.do_call/2
(mini) lib/mini/endpoint.ex:1: Mini.Endpoint.phoenix_pipeline/1
(mini) lib/plug/debugger.ex:123: Mini.Endpoint."call (overridable 3)"/2
(mini) lib/mini/endpoint.ex:1: Mini.Endpoint.call/2
(plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
(cowboy) /Users/billc/dev/mini/deps/cowboy/src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4
I've executed a request mocking the JSON data structure using Insomnia with success. I sent both requests to Httpbin and compared. The only difference I can find is the Content-type has duplicate application/json entries for the request sent by HTTPoison. But, I can find no reason or option to prevention the duplicate value. Nor any reason why Phoenix would choke on it.