# Middleware TL;DR: `adapter(middleware3(middleware2(middleware1(env, next, options))))` Middleware in `Tesla` extends the request/response pipeline. Requests pass through a stack of middleware before reaching the adapter, allowing modifications to both requests and responses. Middleware can be a module implementing `Tesla.Middleware` behaviour or a function matching `c:Tesla.Middleware.call/3`. There is no distinction between request and response middleware; it's about when you execute `Tesla.run/2`. The middleware stack is processed by calling `Tesla.run/2` until it reaches the adapter. ## Writing Middleware Example of a custom middleware module: ```elixir defmodule Tesla.Middleware.MyCustomMiddleware do @behaviour Tesla.Middleware @impl Tesla.Middleware def call(env, next, options) do # Actions before calling the next middleware # ... Tesla.run(env, next) # Actions after calling the next middleware # ... end end ``` A request logger middleware example: ```elixir defmodule MyApp.Tesla.Middleware.Logger do require Logger @behaviour Tesla.Middleware def call(env, next, _) do Logger.info("Request: #{inspect(env)}") case Tesla.run(env, next) do {:ok, env} -> Logger.info("Response: #{inspect(env)}") {:ok, env} {:error, reason} -> Logger.error("Error: #{inspect(reason)}") {:error, reason} end end end ``` ## Production-Ready Middleware Pipeline Example In a production application, you might combine built-in and custom middleware. Here's an example pipeline: ```elixir defmodule MyApp.ServiceName do defp middleware do base_url = "..." token = "..." [ # Preserve the original request, should be the first middleware in the # pipeline to preserve the original request. Tesla.Middleware.KeepRequest, # Set the base URL {Tesla.Middleware.BaseUrl, base_url}, # Add headers {Tesla.Middleware.Headers, [{"user-agent", "MyApp/1.0"}]}, # Add authorization {Tesla.Middleware.BearerAuth, [token: token]}, # Process the body (encoding, compression) # Use string keys for untrusted input Tesla.Middleware.JSON, # Compress the request and response # Tesla.Middleware.Compression, # Optional OpenTelemetry middleware. Be careful adding `Tesla.Middleware.PathParams` # before this middleware since you want to have low cardinality attribute # values, therefore, you want the URL template. # Tesla.Middleware.OpenTelemetry # Keep the telemetry and logging as close as possible to the actual request # being made. # Log requests and responses Tesla.Middleware.Logger, # Telemetry of the Request Tesla.Middleware.Telemetry, # Replaces the Path Params, you may want keep it at the end when telemetry # packages prefer to work with the URL template. Tesla.Middleware.PathParams, ] end end ``` See [built-in middlewares](https://github.com/elixir-tesla/tesla/tree/master/lib/tesla/middleware) for more examples.