Background
I have a Plug Router that has some simple endpoints. One of these endpoints is a put method that receives a JSON body. I want to use Plug.Parsers
to decode the body before processing it but I am having errors and I don’t know why.
Code
This is my router. Requests come here to be dispatched:
defmodule Api do
use Plug.Router
plug :match
plug Plug.Parsers, parsers: [:urlencoded, :json],
json_decoder: Jason
plug :dispatch
put "/cars" do
IO.inspect conn
Conn.send_resp(conn, Status.code(:ok), "OK")
end
end
To exercise this code, I have the following test:
test "returns 200 OK when the list of cars is loaded correctly" do
# Arrange
body_params = "[
{
\"id\": 1,
\"number\": 4
},
{
\"id\": 2,
\"number\": 6
}
]"
conn =
:put
|> conn("/cars")
|> put_req_header("accept", "application/json")
|> put_req_header("content-type", "application/json")
|> put_body_params(body_params)
# Act
conn = Api.call(conn, @opts)
# Assert
assert conn.state == :sent
assert conn.status == 200
assert conn.resp_body == "OK"
end
According to my knowledge, this should work, but I get the following error:
test PUT /cars returns 200 OK when the list of cars is loaded correctly (ApiTest)
test/api_test.exs:69
** (BadMapError) expected a map, got: “[\n {\n "id": 1,\n "number": 4\n },\n {\n "id": 2,\n "number": 6\n }\n ]”
code: conn = Api.call(conn, @opts)
stacktrace:
(stdlib 3.10) :maps.merge(%{}, “[\n {\n "id": 1,\n "seats": 4\n },\n {\n "id": 2,\n "seats": 6\n }\n ]”)
(plug 1.10.4) lib/plug/parsers.ex:354: Plug.Parsers.merge_params/4
(plug 1.10.4) lib/plug/parsers.ex:299: Plug.Parsers.call/2
(api 0.1.0) lib/api.ex:1: Api.plug_builder_call/2
test/api_test.exs:91: (test)
Questions
- Is my configuration of the router incorrect?
- Will the parser be applied to all incoming requests?
- What happens if I get a request that is not JSON? (will the parser ignore it?)
- What am I doing wrong?