elixir-plug / plug

Compose web applications with functions
https://hex.pm/packages/plug
Other
2.88k stars 586 forks source link

Allow testing request body when passing in params #1110

Closed tomasz-tomczyk closed 2 years ago

tomasz-tomczyk commented 2 years ago

I'm writing a small utility function that caches the raw body of the request as suggested in https://github.com/elixir-plug/plug/issues/691 and https://hexdocs.pm/plug/Plug.Parsers.html#module-custom-body-reader that looks like the following:

defmodule RawBody do
  def cache_raw_body(conn, opts \\ []) do
    {:ok, body, conn} = Plug.Conn.read_body(conn, opts)
    conn = update_in(conn.assigns[:raw_body], &[body | &1 || []])
    {:ok, body, conn}
  end
end

When writing a test for it I couldn't get the real values

conn =
  conn(:get, "/test", %{
    "hello" => "world"
  })
  |> RawBody.cache_raw_body()

IO.inspect(conn)
# assigns: %{raw_body: [""]}

conn =
  conn(:post, "/test", %{
    "hello" => "world"
  })
  |> RawBody.cache_raw_body()

IO.inspect(conn)
# assigns: %{raw_body: ["--plug_conn_test--"]},

I thought it might be good to expose the params in both GET and POST handlers, but let me know if I misunderstood anything!

josevalim commented 2 years ago

I believe in this case the better option is to always pass the body as a string, instead of parameters (i.e. make the third argument of get/3 a string). Would that work?

tomasz-tomczyk commented 2 years ago

You're right, I think I assumed the data was provided by params somehow, but this works fine:

assert {:ok, _body, conn} =
        conn(:get, "/test", "{\"hello\":\"world\"")
        |> RawBody.cache_raw_body()

assert conn.assigns.raw_body == ["{\"hello\":\"world\""]

assert {:ok, _body, conn} =
        conn(:post, "/test", "{\"hello\":\"world\"")
        |> RawBody.cache_raw_body()

assert conn.assigns.raw_body == ["{\"hello\":\"world\""]

I'll close, thanks!