# OpenAPI

Tesla does not parse OpenAPI documents or generate client modules. It provides
request values and middleware that generated or hand-written clients can use to
represent OpenAPI parameter serialization.

## Parameter locations

OpenAPI parameter location decides which part of the HTTP request carries a
value. Tesla keeps that boundary in generated or hand-written client code: `in`
chooses the Tesla API, while `style`, `explode`, and `allowReserved` become
serialization options where they apply.

| OpenAPI location | Tesla API |
| --- | --- |
| `path` | `Tesla.OpenAPI.PathTemplate`, `Tesla.OpenAPI.PathParam`, `Tesla.OpenAPI.PathParams`, and `Tesla.Middleware.PathParams` in `:modern` mode |
| `query` | `Tesla.OpenAPI.QueryParam`, `Tesla.OpenAPI.QueryParams`, and `Tesla.Middleware.Query` in `:modern` mode |
| `querystring` | `Tesla.OpenAPI.QueryString` passed directly as the request `:query` |
| `header` | `Tesla.OpenAPI.HeaderParam` and `Tesla.OpenAPI.HeaderParams.to_headers/2` |
| `cookie` | `Tesla.OpenAPI.CookieParam` and `Tesla.OpenAPI.CookieParams.to_headers/2` |

`path` and `query` parameters use middleware because they are transformed into
the final request URL. `header` and `cookie` parameter collections produce raw
header tuples before the request enters the middleware stack.

In `Tesla.Middleware.Query` `:modern` mode, values matching
`Tesla.OpenAPI.QueryParams` definitions use OpenAPI query serialization. Other query
params remain normal Tesla query params.

OpenAPI does not define a global operation flag for rejecting unknown query
parameter names. When a query parameter schema uses `additionalProperties`,
keep that as an object-valued `Tesla.OpenAPI.QueryParam` value. If a generated client
needs a closed set of top-level query names, validate that in the generated
operation module before calling Tesla.

`querystring` is separate from `query` because OpenAPI treats it as the entire
query string value. It must not be mixed with normal query parameters.

## Query string operations

OpenAPI `in: "querystring"` treats the entire query string as one value. Use
`Tesla.OpenAPI.QueryString` for those operations instead of `Tesla.OpenAPI.QueryParam`:

```elixir
defmodule MyApi.Operation.Search do
  alias MyApi.Client
  alias Tesla.OpenAPI.QueryString

  defstruct query_string: nil

  def handle_operation(%Client{} = client, %__MODULE__{} = operation, opts) do
    request_opts = [
      method: :get,
      url: "/search",
      query: QueryString.form!(operation.query_string),
      opts: opts
    ]

    Tesla.request(client.client, request_opts)
  end
end
```

Use `Tesla.OpenAPI.QueryString.raw!/2` when the OpenAPI media type already produced the
exact query string. Do not send `Tesla.OpenAPI.QueryString` through
`Tesla.Middleware.Query` as a normal query map in `:modern` mode, which expects
request values backed by `Tesla.OpenAPI.QueryParams` in `t:Tesla.Env.private/0`.

## Mapping OpenAPI fields

Use the parameter location to choose the Tesla API. Then map only the
serialization fields that Tesla needs at request time:

| OpenAPI field | Tesla mapping |
| --- | --- |
| `name` | Constructor argument, except `querystring`, where the whole query string is the value |
| `in` | Chooses the Tesla API; it is not passed as an option |
| `style` | `:style` atom |
| `explode` | `:explode` boolean |
| `allowReserved` | `:allow_reserved` boolean where supported |
| `required`, `deprecated`, `schema`, `content` | Code generation or validation concern, not a Tesla serialization option |

OpenAPI style names that do not belong to a parameter location are not accepted
by the corresponding Tesla value object. Tesla options use Elixir atoms and
snake case, so OpenAPI `pipeDelimited`, `deepObject`, and `allowReserved` become
`:pipe_delimited`, `:deep_object`, and `:allow_reserved`.

`schema.additionalProperties` affects the value a generated client accepts for
an object parameter. It does not become a `Tesla.OpenAPI.QueryParam` option.

For a generated-operation walkthrough, see
[Working with OpenAPI parameters](../howtos/openapi-parameters.md).

For quick lookup while implementing generated clients, see the
[OpenAPI Cheat Sheet](../cheatsheets/openapi.cheatmd).
