You need to access the body before it has been modified by a subsequent Plug.
Here is an example in Plug.Parsers docs that exposes this very use case ![]()
Edit : note that you can also do that with a custom Parser that runs before other Plug.Parsers. You can pattern match on the request path if you wish to avoid copying the raw body for other kind of requests.
@behaviour Plug.Parsers
alias Plug.Conn
def parse(%{request_path: "/specific_path"} = conn, _type, _subtype, _headers, opts) do
case Conn.read_body(conn, opts) do
{:ok, body, conn} ->
{:ok, %{raw_body: body}, conn}
{:more, _data, conn} ->
{:error, :too_large, conn}
end
end
def parse(conn, _type, _subtype, _headers, _opts), do: {:next, conn}
Check for exhaustiveness with the docs, because I cannot verify it today.
After that, the %{raw_body: r} map gets merged into conn.params. You can access it by pattern matching on conn.params in your controller.
def handle_webhook(%{params: %{raw_body: raw_body}} = conn, params) do
There are many ways to get to the desired result, but the goal is the same : preserve the raw request body.






















