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 usePlug.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With