The library's request entry point.
Mount this plug under whatever path your host application uses (e.g.
forward "/img", to: Image.Plug, init_opts: [...] for
Plug.Router, or plug Image.Plug, [...] from a Phoenix
endpoint).
Passthrough
A request whose URL the configured provider does not recognise as an
image request is passed through untouched: the plug returns the
connection un-halted and unsent so the host application's remaining
plugs handle it. This makes plug Image.Plug safe to mount at the
root of a Phoenix endpoint ahead of your router — only genuine image
URLs are claimed; everything else flows on. A URL that clearly
intends an image request but is malformed still produces an error
response.
When the plug is mounted as the sole plug of a standalone server
(for example a Bandit plug: entry with nothing downstream), an
unrecognised URL has nowhere to pass through to; add a fallback
route (e.g. a Plug.Router match _ that returns 404) if you need
to serve non-image paths from the same endpoint.
Runtime configuration for releases
A Phoenix endpoint calls a plug's init/1 at compile time, so
options passed inline to plug Image.Plug, ... — including a
provider's :mount path — are frozen into the compiled module and
cannot be read from config/runtime.exs or environment variables at
boot. To configure the plug at runtime (the usual case for an Elixir
release), pass otp_app::
# endpoint.ex
plug Image.Plug, otp_app: :my_app
# config/runtime.exs
config :my_app, Image.Plug,
provider: {Image.Plug.Provider.Cloudflare, mount: System.fetch_env!("IMAGE_MOUNT")},
source_resolver: {Image.Plug.SourceResolver.HTTP, []}In this mode init/1 stores only the app reference; the full
configuration is read from the application environment and validated
on the first request, then memoized. Inline options given alongside
otp_app: act as defaults that the application-environment config
overrides per key. Pass :key to override the config key (it
defaults to Image.Plug).
Alternatively, without any Image.Plug-specific option, Phoenix's own
config :my_app, MyAppWeb.Endpoint, plug_init_mode: :runtime makes
the endpoint run every plug's init/1 at boot, after which inline
System.get_env/1 calls resolve; note that this applies to the whole
endpoint, not just this plug.
Request lifecycle
Each request flows through:
provider.parse/2— produces either a fully-formed pipeline + source, a variant lookup + source, or a passthrough source.Variant resolution against the configured
Image.Plug.VariantStore. Variant URLs of the form/<account>/<image-id>/<variant-name>are expanded to the stored pipeline; ad-hoc URLs skip this step.source_resolver.load/2— opens the source as aVix.Vips.Image, preferring streaming decode.Image.Plug.Pipeline.Encoder.encode/3— produces a streaming body when possible.The plug pipes the body to the client via
Plug.Conn.send_chunked/2+Plug.Conn.chunk/2. Buffered bytes bodies usePlug.Conn.send_resp/3.
Summary
Functions
Handles a single request end-to-end.
Returns the default telemetry prefix used by the request plug.
Deletes a variant by name.
Fetches a variant by name.
Validates configuration and returns an opaque options struct passed
through to every call/2 invocation.
Lists every variant in the store.
Inserts or updates a variant.
Returns the library version as a string.
Types
Functions
@spec call(Plug.Conn.t(), Image.Plug.Options.t() | runtime_config()) :: Plug.Conn.t()
Handles a single request end-to-end.
@spec default_telemetry_prefix() :: [atom(), ...]
Returns the default telemetry prefix used by the request plug.
Returns
- The list of atoms
[:image_plug].
Examples
iex> Image.Plug.default_telemetry_prefix()
[:image_plug]
Deletes a variant by name.
Returns
:okon success.{:error, :not_found}if the variant does not exist.
@spec get_variant( String.t(), keyword() ) :: {:ok, Image.Plug.Variant.t()} | {:error, :not_found}
Fetches a variant by name.
Returns {:ok, variant} or {:error, :not_found}.
Examples
iex> case Image.Plug.get_variant("public") do
...> {:ok, variant} -> variant.name
...> {:error, _} -> nil
...> end
"public"
@spec init(keyword()) :: Image.Plug.Options.t() | runtime_config()
Validates configuration and returns an opaque options struct passed
through to every call/2 invocation.
Raises ArgumentError if required configuration is missing or
malformed. Configuration errors are programmer errors and must surface
at boot time, not per-request.
Runtime configuration
Pass otp_app: :my_app to read the configuration from the application
environment (Application.get_env(:my_app, Image.Plug)) on the first
request instead of at compile time. This is what lets an Elixir release
configure the plug — for example a runtime :mount path — from
config/runtime.exs. Any inline options are used as defaults that the
application-environment config overrides per key. An optional :key
overrides the config key (defaulting to Image.Plug). In this mode
configuration errors surface on the first request rather than at boot.
@spec list_variants(keyword()) :: {:ok, [Image.Plug.Variant.t()]}
Lists every variant in the store.
Returns
{:ok, [variant]}— the order is store-defined (the default ETS store sorts by name).
@spec put_variant(Image.Plug.Variant.t() | String.t(), term(), keyword()) :: {:ok, Image.Plug.Variant.t()} | {:error, term()}
Inserts or updates a variant.
Arguments
name_or_variantis either a variant name string or a completeImage.Plug.Variantstruct.When the first argument is a name, the second argument is either a Cloudflare-style options string, an
Image.Plug.Pipelinestruct, or a{provider_module, options_string}tuple.
Options
:store—{module, options}tuple identifying the store. Defaults to{Image.Plug.VariantStore.ETS, []}.:metadata— arbitrary metadata map stored on the variant.:never_require_signed_urls?— boolean, defaults tofalse.
Returns
{:ok, variant}on success.{:error, reason}on failure (e.g. invalid options string).
@spec version() :: String.t()
Returns the library version as a string.
Returns
- A semver-like version string such as
"0.1.0-dev".
Examples
iex> is_binary(Image.Plug.version())
true