# `PactEx.HTTP`
[🔗](https://github.com/arctarus/pact_ex/blob/v0.1.0/lib/pact_ex/http.ex#L1)

Builder functions for HTTP interactions.

These functions only build data. Nothing reaches the native layer until
the interaction is applied to a mock server.

    PactEx.HTTP.interaction("get user")
    |> PactEx.HTTP.given("user exists", %{"id" => 1})
    |> PactEx.HTTP.with_request(:get, "/users/1")
    |> PactEx.HTTP.will_respond_with(200, body: %{"id" => 1})

# `given`

```elixir
@spec given(PactEx.HTTP.Interaction.t(), String.t(), map() | nil) ::
  PactEx.HTTP.Interaction.t()
```

Adds a provider state. States keep the order of the calls.

`params` is an optional map of state parameters.

Raises `FunctionClauseError` if `state` is not a string, or if `params` is
neither a map nor `nil`.

# `interaction`

```elixir
@spec interaction(String.t()) :: PactEx.HTTP.Interaction.t()
```

Starts an interaction with the given description.

Raises `FunctionClauseError` if `description` is not a string.

# `will_respond_with`

```elixir
@spec will_respond_with(PactEx.HTTP.Interaction.t(), 100..599, keyword()) ::
  PactEx.HTTP.Interaction.t()
```

Sets the expected response. Calling it again replaces the previous response.

`status` must be an integer from 100 to 599.

## Options

  * `:headers` - response headers: a map, a keyword list or a list of
    `{name, value}` tuples, as for `with_request/4`. Defaults to `%{}`.
  * `:body` - response body. Defaults to `nil`.
  * `:content_type` - content type of the body. Defaults to `nil`.

Raises `ArgumentError` on unknown options, or if `:headers` is neither a map,
a keyword list nor a list of `{name, value}` tuples. Raises
`FunctionClauseError` if `status` is not an integer from 100 to 599.

# `with_request`

```elixir
@spec with_request(
  PactEx.HTTP.Interaction.t(),
  atom() | String.t(),
  String.t() | map(),
  keyword()
) ::
  PactEx.HTTP.Interaction.t()
```

Sets the expected request.

`method` is an atom or a string and is stored upper-cased. `path` is a
string or a matcher map. Calling it again replaces the previous request.

## Options

  * `:query` - query parameters. Defaults to `%{}`. See below.
  * `:headers` - request headers. Defaults to `%{}`. See below.
  * `:body` - request body. Defaults to `nil`.
  * `:content_type` - content type of the body. Defaults to `nil`.

`:query` and `:headers` take a map, a keyword list or a list of
`{name, value}` tuples. A name is a string or an atom. Values are as in a map
(strings, numbers, booleans, matchers, or a list of them):

    query: %{"tag" => ["a", "b"], page: 2}
    query: [page: 2, tag: "a", tag: "b"]
    headers: [{"x-id", "1"}, accept: "application/json"]

A map is kept as you wrote it. A list is turned into a map with string names.
A name that repeats gets all its values, in order, so `[tag: "a", tag: "b"]`
is `%{"tag" => ["a", "b"]}`. A list value counts as several values:
`[tag: ["a", "b"], tag: "c"]` is `%{"tag" => ["a", "b", "c"]}`, and an empty
list adds nothing (a name whose values are all empty is an error when the
interaction is applied, as in a map). Query names are case-sensitive, so
`"Tag"` and `"tag"` stay apart. Header names are not: in a list,
`[{"Accept", "a"}, accept: "b"]` is `%{"Accept" => ["a", "b"]}`, with the
first spelling kept. That includes `Content-Type`: a list merges its
spellings into one header with several values, while a map with two
spellings of it is an error when the interaction is applied. A map is never
merged.

A header name that is an atom is written as Req writes it: underscores
become dashes and ASCII letters lower case, so `x_request_id: "1"` is the
header `"x-request-id"` and `content_type: "text/plain"` is `Content-Type`.
This holds for a map as well as for a list. A header name that is a string
is used as it is (`"x_id"` stays `"x_id"`). Query names are not changed:
`page_size: 2` is the parameter `"page_size"`.

Raises `ArgumentError` on unknown options, or if `:query` or `:headers` is
neither a map, a keyword list nor a list of `{name, value}` tuples (a name
must be a string or an atom other than `nil`, `true` and `false`). Raises
`FunctionClauseError` if `method` is not a string or an atom other than
`nil`, `true` and `false`, or if `path` is not a string or a map.

---

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