Fl4m3Ph03n1x
How to use Plug.Parsers?
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?
Marked As Solved
al2o3cr
Using put_body_params entirely short-circuits the parsing in Plug.Parser - that only happens when body_params is a %Plug.Unfetched{}.
You want to set the body to the unparsed JSON when calling Plug.Test.conn/3:
conn(:put, "/cars", body_params_json_string)
|> put_request_header("content-type", "application/json")
|> put_request_header("accept", "application/json")
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex









