# Customizing Requests with `prepare_req`
Every client module generated by `use Grephql` includes an overridable `prepare_req/1` callback. It receives the fully built `%Req.Request{}` just before it is sent, giving you a hook to attach [Req response steps](https://hexdocs.pm/req/Req.Request.html#module-response-steps), add headers, or apply any other request-level customization.
## How It Works
1. Override `prepare_req/1` in your client module
2. In a Req response step, use `Grephql.Result.put_resp_assign/3` to stash values from the response
3. After decoding, those values appear in `result.assigns`
```elixir
defmodule MyApp.API do
use Grephql,
otp_app: :my_app,
source: "priv/schemas/api.json",
endpoint: "https://api.example.com/graphql"
def prepare_req(req) do
Req.Request.append_response_steps(req,
capture_request_id: fn {req, resp} ->
request_id = Req.Response.get_header(resp, "x-request-id")
{req, Grephql.Result.put_resp_assign(resp, :request_id, request_id)}
end
)
end
defgql :get_user, ~GQL"""
query GetUser($id: ID!) {
user(id: $id) { name }
}
"""
end
{:ok, result} = MyApp.API.get_user(%{id: "1"})
result.assigns[:request_id] #=> ["req-abc-123"]
```
## Storing Multiple Values
Call `put_resp_assign/3` multiple times to store different pieces of metadata:
```elixir
def prepare_req(req) do
Req.Request.append_response_steps(req,
capture_metadata: fn {req, resp} ->
resp =
resp
|> Grephql.Result.put_resp_assign(:extensions, resp.body["extensions"])
|> Grephql.Result.put_resp_assign(:request_id, Req.Response.get_header(resp, "x-request-id"))
{req, resp}
end
)
end
```
## Testing
Use `Req.Test` as usual. Include the metadata you want to capture in the stubbed response:
```elixir
test "captures request metadata" do
Req.Test.stub(MyApp.API, fn conn ->
conn
|> Plug.Conn.put_resp_header("x-request-id", "test-123")
|> Req.Test.json(%{
"data" => %{"user" => %{"name" => "Alice"}}
})
end)
assert {:ok, result} = MyApp.API.get_user(%{id: "1"})
assert result.assigns[:request_id] == ["test-123"]
end
```
## Example: Shopify Rate Limiting via Extensions
Shopify's GraphQL API returns rate-limit and cost information in the `extensions` field:
```json
{
"data": { "products": { ... } },
"extensions": {
"cost": {
"requestedQueryCost": 12,
"actualQueryCost": 10,
"throttleStatus": {
"currentlyAvailable": 980,
"maximumAvailable": 1000.0,
"restoreRate": 50.0
}
}
}
}
```
Capture it with `prepare_req/1`:
```elixir
defmodule MyApp.Shopify do
use Grephql,
otp_app: :my_app,
source: "priv/schemas/shopify.json",
endpoint: "https://myshop.myshopify.com/admin/api/graphql.json"
def prepare_req(req) do
Req.Request.append_response_steps(req,
capture_extensions: fn {req, resp} ->
{req, Grephql.Result.put_resp_assign(resp, :extensions, resp.body["extensions"])}
end
)
end
defgql :get_products, ~GQL"""
query GetProducts($first: Int!) {
products(first: $first) {
edges {
node {
title
}
}
}
}
"""
end
```
Then use the captured cost data to throttle API calls:
```elixir
{:ok, result} = MyApp.Shopify.get_products(%{first: 10})
throttle_status = result.assigns[:extensions]["cost"]["throttleStatus"]
throttle_status["currentlyAvailable"] #=> 980
throttle_status["restoreRate"] #=> 50.0
```
```elixir
defmodule MyApp.Shopify.RateLimiter do
def maybe_throttle(%Grephql.Result{assigns: assigns}) do
case assigns[:extensions] do
%{"cost" => %{"throttleStatus" => %{"currentlyAvailable" => available}}}
when available < 100 ->
Process.sleep(1_000)
_other ->
:ok
end
end
end
```
## API Reference
- `prepare_req/1` — overridable callback on client modules, receives the `%Req.Request{}` before it is sent
- `Grephql.Result.put_resp_assign/3` — stores a key-value pair on the Req response for later transfer to `Result.assigns`
- `Grephql.Result` — the `:assigns` field (default `%{}`) holds all values stored via `put_resp_assign/3`