3
votes

I'm playing around with the plug router and trying to read the body of a simple post request in my router:

The form

<form action="/create_item" method="post">
  <input type="text" value="whatever" name="name">
  <input type="number" value="99" name="age">
  <input type="submit">
</form>

My router

post("/create_item") do
  {:ok, data, _conn} = read_body(conn)
  send_resp(conn, 200, data)
end

If I submit my form, this will render name=input-value to the page, but then I would have to parse that string to just get the value. This smells the the wrong way to do it.

From my little experience with elixir, it seems like I should be doing something like pattern-matching on the read_body(conn) to pull out each key: value from my form, but I cannot find anything about this in the plug docs. I tried digging through the phoenix source for ideas, but that's a bit beyond my elixir knowledge. Is there an obvious parse_form_data/1 function that I'm missing?

3

3 Answers

11
votes

Plug.Conn.read_body/1 just reads the body of the request, without parsing it. To parse the body, you usually want to use the Plug.Parsers plug, which reads and parses the body of the request based on its content type.

For example, if you plug it like this:

plug Plug.Parsers, parsers: [:urlencoded]

everywhere after that in the pipeline will have conn.params available.

0
votes
conn = parse(conn)
name = conn.params["name"]
age = conn.params["age"]

def parse(conn, opts \\ []) do
    opts = Keyword.put_new(opts, :parsers, [Plug.Parsers.URLENCODED, Plug.Parsers.MULTIPART])
    Plug.Parsers.call(conn, Plug.Parsers.init(opts))
end
0
votes

Recently I came across this question. That is the way I used:

{:ok, body, conn} = Plug.Conn.read_body(conn)
parsed_body = Poison.Parser.parse!(body)
IO.puts "The body is #{parsed_body}, #{inspect is_map(parsed_body))"

I think maybe another way to solve, so now I am reading Plug module doc.