# Adapter

An adapter in Tesla implements the `Tesla.Adapter` behaviour and handles the
actual HTTP communication. It's the final step in the middleware chain,
responsible for sending requests and receiving responses.

## Writing an Adapter

You can create a custom adapter by implementing the `Tesla.Adapter` behaviour.
Here's an example:

```elixir
defmodule Tesla.Adapter.Req do
  @behaviour Tesla.Adapter

  @impl Tesla.Adapter
  def call(env, _opts) do
    req = Req.new(
      url: Tesla.build_url(env),
      method: env.method,
      headers: env.headers,
      body: env.body
    )

    case Req.request(req) do
      {:ok, %Req.Response{} = resp} ->
        {:ok, %Tesla.Env{env | status: resp.status, headers: resp.headers, body: resp.body}}

      {:error, reason} ->
        {:error, reason}
    end
  end
end
```

## Setting the Adapter

If you don't specify an adapter when creating a client with `Tesla.client/2`,
`Tesla` uses the adapter configured in the `:tesla` application environment.
By default, Tesla uses `Tesla.Adapter.Httpc`, which relies on Erlang's built-in
`httpc`.

> #### :httpc as default Adapter {: .error}
> The default `httpc` adapter is not recommended for production because it
> doesn't validate SSL certificates and has other issues. Consider using `Mint`,
> `Finch`, or `Hackney` adapters instead.

## Adapter Options

You can pass options to adapters in several ways:

- In the application configuration:

  ```elixir
  config :tesla, adapter: {Tesla.Adapter.Hackney, [recv_timeout: 30_000]}
  ```

- When creating a client:

  ```elixir
  defmodule MyService do
    def client(...) do
      middleware = [...]
      adapter = {Tesla.Adapter.Hackney, [recv_timeout: 30_000]}
      Tesla.client(middleware, adapter)
    end
  end
  ```

- Directly in request functions:

  ```elixir
  Tesla.get(client, "/", opts: [adapter: [recv_timeout: 30_000]])
  ```

## Method Support

All adapters support the standard HTTP methods: HEAD, GET, DELETE, TRACE,
OPTIONS, POST, PUT, and PATCH.

The QUERY method ([RFC 10008](https://www.rfc-editor.org/rfc/rfc10008)) is
supported by the `Hackney`, `Gun`, `Mint`, and `Finch` adapters. The clients
underlying the remaining adapters accept only a fixed set of methods, so QUERY
requests fail with an error:

- `Tesla.Adapter.Httpc` returns `{:error, :invalid_method}`. The error comes
  from `:httpc` itself, so QUERY will start working automatically once OTP
  adds support for it.
- `Tesla.Adapter.Ibrowse` returns `{:error, :method_not_supported_by_adapter}`.

## About :httpc adapter and security issues

[People have complained about `:httpc` adapter in `Tesla` due to
its security issues. The main problem is that `:httpc` does not validate SSL
certificates by default][0]. Which, we believe, is a serious security issue and
should be addressed by `:httpc` itself.

As much as we would like to fix it, we can't, because we are unsure if it would
break existing code. We are not planning to fix it in `Tesla` due to backward
compatibility. We may reconsider this decision for a version 2.0.

[0]: https://github.com/elixir-tesla/tesla/issues/293
