# `HTTPower.Request`
[🔗](https://github.com/mdepolli/httpower/blob/v0.22.0/lib/httpower/request.ex#L1)

Internal request representation for the HTTPower pipeline.

This struct wraps request data and provides a context for features to
communicate and store data as requests flow through the pipeline.

## Fields

- `method` - HTTP method (`:get`, `:post`, `:put`, `:delete`)
- `url` - Request URL (string)
- `body` - Request body (string, map, or nil)
- `headers` - Request headers (map)
- `opts` - Request options (keyword list)
- `private` - Private storage for feature communication (map)

## The `private` Field

The `private` field is a map that features can use to:
- Store data for post-request processing
- Pass data between features
- Cache expensive computations

Example:

    # Feature stores data in private
    def handle_request(request, _config) do
      private = Map.put(request.private, :circuit_breaker, {key, config})
      {:ok, %{request | private: private}}
    end

    # Later, post-request handler reads it
    circuit_info = Map.get(request.private, :circuit_breaker)

## Usage

This struct is internal to HTTPower and created automatically. Users
typically don't need to create Request structs directly.

However, when implementing custom features, you'll receive and return
Request structs in your `handle_request/2` callback:

    defmodule MyFeature do
      @behaviour HTTPower.Middleware

      def handle_request(request, _config) do
        # Modify the request
        updated_request = %{request | headers: new_headers}
        {:ok, updated_request}
      end
    end

# `t`

```elixir
@type t() :: %HTTPower.Request{
  body: term(),
  headers: map(),
  method: :get | :post | :put | :delete | :patch | :head | :options,
  opts: keyword(),
  private: map(),
  url: URI.t()
}
```

# `get_header`

```elixir
@spec get_header(t(), String.t(), String.t() | nil) :: String.t() | nil
```

Retrieves a header value.

Returns `nil` if the header doesn't exist, or the provided default value.

## Examples

    iex> uri = URI.parse("https://example.com")
    iex> request = HTTPower.Request.new(:get, uri, nil, %{"accept" => "application/json"})
    iex> HTTPower.Request.get_header(request, "accept")
    "application/json"

    iex> uri = URI.parse("https://example.com")
    iex> request = HTTPower.Request.new(:get, uri)
    iex> HTTPower.Request.get_header(request, "missing")
    nil

    iex> uri = URI.parse("https://example.com")
    iex> request = HTTPower.Request.new(:get, uri)
    iex> HTTPower.Request.get_header(request, "missing", "default")
    "default"

# `get_private`

```elixir
@spec get_private(t(), atom(), term()) :: term()
```

Retrieves a value from the request's private storage.

Returns `nil` if the key doesn't exist, or the provided default value.

## Examples

    iex> uri = URI.parse("https://example.com")
    iex> request = HTTPower.Request.new(:get, uri)
    iex> request = HTTPower.Request.put_private(request, :my_key, "my_value")
    iex> HTTPower.Request.get_private(request, :my_key)
    "my_value"

    iex> uri = URI.parse("https://example.com")
    iex> request = HTTPower.Request.new(:get, uri)
    iex> HTTPower.Request.get_private(request, :missing_key)
    nil

    iex> uri = URI.parse("https://example.com")
    iex> request = HTTPower.Request.new(:get, uri)
    iex> HTTPower.Request.get_private(request, :missing_key, "default")
    "default"

# `merge_headers`

```elixir
@spec merge_headers(t(), map()) :: t()
```

Updates the request headers by merging with existing headers.

Request-level headers take precedence over existing headers.

## Examples

    iex> uri = URI.parse("https://example.com")
    iex> request = HTTPower.Request.new(:get, uri, nil, %{"accept" => "application/json"})
    iex> request = HTTPower.Request.merge_headers(request, %{"authorization" => "Bearer token"})
    iex> request.headers
    %{"accept" => "application/json", "authorization" => "Bearer token"}

    iex> uri = URI.parse("https://example.com")
    iex> request = HTTPower.Request.new(:get, uri, nil, %{"accept" => "application/json"})
    iex> request = HTTPower.Request.merge_headers(request, %{"accept" => "application/xml"})
    iex> request.headers
    %{"accept" => "application/xml"}

# `new`

```elixir
@spec new(atom(), URI.t(), term(), map(), keyword()) :: t()
```

Creates a new Request struct.

The URL must be a validated URI struct (not a string). This ensures
URL validation happens early in the request pipeline.

## Examples

    iex> uri = URI.parse("https://api.example.com")
    iex> request = HTTPower.Request.new(:get, uri)
    iex> request.method
    :get
    iex> request.url.scheme
    "https"
    iex> request.url.host
    "api.example.com"
    iex> request.body
    nil
    iex> request.headers
    %{}
    iex> request.opts
    []
    iex> request.private
    %{}

    iex> uri = URI.parse("https://api.example.com")
    iex> request = HTTPower.Request.new(:post, uri, "data", %{"content-type" => "text/plain"})
    iex> request.method
    :post
    iex> request.body
    "data"
    iex> request.headers
    %{"content-type" => "text/plain"}

# `put_header`

```elixir
@spec put_header(t(), String.t(), String.t()) :: t()
```

Updates a specific header value.

## Examples

    iex> uri = URI.parse("https://example.com")
    iex> request = HTTPower.Request.new(:get, uri)
    iex> request = HTTPower.Request.put_header(request, "authorization", "Bearer token")
    iex> request.headers
    %{"authorization" => "Bearer token"}

# `put_private`

```elixir
@spec put_private(t(), atom(), term()) :: t()
```

Stores a value in the request's private storage.

## Examples

    iex> uri = URI.parse("https://example.com")
    iex> request = HTTPower.Request.new(:get, uri)
    iex> request = HTTPower.Request.put_private(request, :my_key, "my_value")
    iex> request.private
    %{my_key: "my_value"}

---

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