# `PhoenixMountable.RawBody`
[🔗](https://github.com/hattoriai/phoenix_mountable/blob/v0.2.4/lib/phoenix_mountable/raw_body.ex#L2)

The body of a request as it was sent, for the routes that check a
signature of it: a mail provider's webhooks, GitHub's, Stripe's.

In a Phoenix app the endpoint's `Plug.Parsers` reads the body before the
router, and a body can be read once. A Rails engine's controller can
still read it (Rack keeps it rewindable); a library's route in Phoenix
needs the endpoint to keep a copy. One reader keeps it for every
library, given to `Plug.Parsers` with the app's router:

    plug Plug.Parsers,
      parsers: [:urlencoded, :multipart, :json],
      pass: ["*/*"],
      body_reader: {PhoenixMountable.RawBody, :read_body, [MyAppWeb.Router]},
      json_decoder: Phoenix.json_library()

`use PhoenixMountable.Install, raw_body: true` adds it to the app's
endpoint.

## Which requests

Before it reads a body, the reader asks the router which plug the
request will reach (`Phoenix.Router.route_info/4`, through the routers
it forwards to), and keeps a copy only when that plug says it needs the
body as sent:

    defmodule MyLib.Webhook do
      use PhoenixMountable.RawBody
      # every route to this plug
    end

    defmodule MyLibWeb.HookController do
      use MyLibWeb, :controller
      use PhoenixMountable.RawBody, only: [:create]
      # the routes to these actions
    end

So nothing depends on a route's path, scope or pipeline: the app can
move and rename the routes, and their bodies are kept. Every other
request is read as `Plug.Conn.read_body/2` reads it, with one lookup in
the router's compiled routes the first time, and nothing kept.

The router can be a list of routers (an app with more than one
endpoint's worth, or a router no forward reaches).

## Reading it

In the plug, `fetch/2` gives the body: the copy the reader kept, or the
body itself when the parsers left it unread (a type they `pass`, such as
a raw email's `message/rfc822`).

    {:ok, body, conn} = PhoenixMountable.RawBody.fetch(conn, 1_000_000)

# `__using__`
*macro* 

Marks a plug, or a controller's actions (`only:`), as needing the body
of their requests as it was sent.

# `fetch`

```elixir
@spec fetch(Plug.Conn.t(), pos_integer()) ::
  {:ok, binary(), Plug.Conn.t()} | {:error, :too_large | :no_raw_body | term()}
```

The body of the request as it was sent, at most `max` bytes: the copy
`read_body/3` kept, or the body read now when the parsers left it
unread. `{:error, :too_large}` past `max`, and `{:error, :no_raw_body}`
when the parsers read it without keeping it (the endpoint has not got
the reader, or the route's plug does not `use PhoenixMountable.RawBody`).

# `read_body`

```elixir
@spec read_body(Plug.Conn.t(), keyword(), module() | [module()]) ::
  {:ok, binary(), Plug.Conn.t()}
  | {:more, binary(), Plug.Conn.t()}
  | {:error, term()}
```

A body reader for `Plug.Parsers` (`body_reader: {PhoenixMountable.RawBody,
:read_body, [router]}`): reads the body as `Plug.Conn.read_body/2` does,
and keeps a copy of it for the routes that want it.

# `wanted?`

```elixir
@spec wanted?(module(), String.t(), [String.t()], String.t()) :: boolean()
```

Whether the request to `path_info` reaches a plug that wants its body
as sent, through the routers `router` forwards to.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
