HTTP Configuration
Copy MarkdownSycophant uses Tesla as its HTTP layer. You can configure the adapter, add middleware, and customize transport behaviour through application config.
Tesla Adapter
By default, Sycophant uses whatever Tesla adapter is configured globally (typically Hackney). To use a different adapter:
# config/config.exs or config/runtime.exs
config :sycophant, :tesla,
adapter: Tesla.Adapter.MintAdapters can also receive options as a tuple:
config :sycophant, :tesla,
adapter: {Tesla.Adapter.Mint, [protocols: [:http2]]}Available Adapters
Any Tesla adapter works. Common choices:
| Adapter | Package | Notes |
|---|---|---|
Tesla.Adapter.Hackney | :hackney | Default in most Tesla setups |
Tesla.Adapter.Mint | :mint | Lightweight, HTTP/2 support |
Tesla.Adapter.Finch | :finch | Connection pooling, HTTP/2 |
Tesla.Adapter.Quiver | :quiver | High-performance, HTTP/2 pools |
For Finch, you need to start a pool in your supervision tree:
# In your Application.start/2
children = [
{Finch, name: MyApp.Finch}
]
# config/runtime.exs
config :sycophant, :tesla,
adapter: {Tesla.Adapter.Finch, name: MyApp.Finch}Custom Middleware
Add Tesla middleware that runs on every Sycophant request:
config :sycophant, :tesla,
middlewares: [Tesla.Middleware.Logger]Multiple middleware are applied in order:
config :sycophant, :tesla,
adapter: Tesla.Adapter.Mint,
middlewares: [
Tesla.Middleware.Logger,
{Tesla.Middleware.Retry, delay: 1000, max_retries: 3},
{Tesla.Middleware.Timeout, timeout: 30_000}
]Your custom middleware is appended after Sycophant's built-in middleware (BaseUrl, PathParams, JSON/Headers) and auth middleware.
How the Client Is Built
For each request, Sycophant constructs a fresh Tesla client with this middleware stack:
Synchronous requests:
Tesla.Middleware.BaseUrl-- sets the provider's base URLTesla.Middleware.PathParams-- interpolates URL path parametersTesla.Middleware.JSON-- encodes/decodes JSON bodies- Auth middleware -- provider-specific (Bearer, x-api-key, SigV4, etc.)
- Your custom middleware from config
SSE streaming requests:
Tesla.Middleware.BaseUrlTesla.Middleware.PathParamsTesla.Middleware.Headers-- setsContent-Type: application/jsonTesla.Middleware.SSE-- parses Server-Sent Events- Auth middleware
- Your custom middleware
The adapter is configured with response: :stream for streaming requests
automatically.
Environment-specific Configuration
Use different adapters per environment:
# config/dev.exs
config :sycophant, :tesla,
middlewares: [Tesla.Middleware.Logger]
# config/test.exs
config :sycophant, :tesla,
adapter: {Tesla.Adapter.Quiver, name: Sycophant.Quiver},
middlewares: [{Sycophant.Tesla.RecorderMiddleware, []}]
# config/prod.exs
config :sycophant, :tesla,
adapter: {Tesla.Adapter.Finch, name: MyApp.Finch},
middlewares: [
{Tesla.Middleware.Timeout, timeout: 60_000}
]Error Mapping
Sycophant maps HTTP status codes to typed errors regardless of adapter:
| Status | Error |
|---|---|
| 401 | AuthenticationFailed |
| 404 | ModelNotFound |
| 429 | RateLimited (parses Retry-After header) |
| 400-499 | BadRequest |
| 500+ | ServerError |
Timeouts surface as Timeout errors. Other connection failures surface as Unknown errors.
Logging Requests
The simplest way to debug HTTP traffic is with Tesla's built-in logger:
config :sycophant, :tesla,
middlewares: [Tesla.Middleware.Logger]For more control, use the filter_headers option to avoid logging API keys:
config :sycophant, :tesla,
middlewares: [
{Tesla.Middleware.Logger,
filter_headers: ["authorization", "x-api-key", "api-key", "x-goog-api-key"]}
]