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.
Example of a custom middleware module:
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:
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
In a production application, you might combine built-in and custom middleware. Here's an example pipeline:
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,
# Preserve original path parameters, should be after KeepRequest
# to preserve the original path parameters tokens
Tesla.Middleware.PathParams,
# 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,
# ------------------------------------------------------------------------
# Keep the telemetry and logging as close as possible to the actual request
# being made.
# Log requests and responses
Tesla.Middleware.Logger,
# Telemetry for timing
{Tesla.Middleware.Telemetry},
# Optional OpenTelemetry middleware
# Tesla.Middleware.OpenTelemetry
]
end
end
See built-in middlewares for more examples.