I am coding an Elixir (1.8) + Plug_Cowboy (2.0.2) + Jason (1.1.2) server. From what I am getting from the documentation, once the Plug parser has passed, I should have everything in body_params
. The problem is that accessing conn.body_params
in my case returns %Plug.Conn.Unfetched{aspect: :body_params}
. Check the code below:
defmodule Test.Router do
use Plug.Router
require Logger
plug :match
plug Plug.Parsers, parsers: [:json],
pass: ["application/json", "text/json"],
json_decoder: Jason
plug :dispatch
post "/test" do
Logger.debug inspect(conn.body_params)
conn
|> put_resp_content_type("text/plain")
|> send_resp(204, "Got it")
end
end
Any idea what is going on?
I test this with:
curl -H "Content-Type: text/json" -d "{one: 1, two: 2}" 127.0.0.1:8080/test
I have tried adding :urlencoded
to parsers, or rearranging the plug order, but to no avail.
Plug.Parsers.JSON
only handles the application/json
content type. This is the reason the body_params
is not being populated. Your test JSON is also invalid - the object property names were not quoted.
curl -H "Content-Type: application/json" -d '{"one": 1, "two": 2}' 127.0.0.1:8080/test
The pass:
option to Plug.Parsers
instructs it to ignore requests of those types for which there is no parser defined (such as text/json
in your case), rather than raise an UnsupportedMediaTypeError
, which is what it would usually do. Adding that option was hiding the error.
You might find it useful to use
Plug.Debugger
during development - it will give you better information of what is happening in unexpected situations.
If for some reason you need to be able to parse JSON with the non-standard text/json
type (because of requests from software you cannot control, for example), you can define a new parser for that type that just wraps up Plug.Parsers.JSON
and rewrites text/json
to application/json
:
defmodule WrongJson do
def init(opts), do: Plug.Parsers.JSON.init(opts)
def parse(conn, "text", "json", params, opts) do
Plug.Parsers.JSON.parse(conn, "application", "json", params, opts)
end
def parse(conn, _type, _subtype, _params, _opts), do: {:next, conn}
end
Then add it to your list of parsers:
plug Plug.Parsers,
parsers: [:json, WrongJson],
json_decoder: Jason
Now text/json
will also work.