IIIFImagePlug.V3 behaviour (IIIFImagePlug v0.6.0)
View SourceThis plug implements the IIIF Image API version 3 (see also https://iiif.io/api/image/3.0).
Summary
Callbacks
Required callback function invoked on image data requests, that maps the given identifier to an image file.
Optional callback function to override the :host evaluated from the Plug.Conn, useful if your Elixir app runs behind a proxy.
Required callback function invoked on information requests (info.json), that maps the given identifier to an
image file.
Optional callback function to override the :port evaluated from the Plug.Conn, useful if your Elixir app runs behind a proxy.
Optional callback function to override the :scheme ("http" or "https") evaluated from the Plug.Conn, useful if your Elixir app runs behind a
proxy.
Optional callback function that lets you override the default plug error response.
Callbacks
@callback data_request(identifier :: String.t()) :: {:ok, IIIFImagePlug.V3.DataRequest.t()} | {:error, IIIFImagePlug.V3.RequestError.t()}
Required callback function invoked on image data requests, that maps the given identifier to an image file.
Returns
{:ok, data_request}on success, whereinfo_requestis aIIIFImagePlug.V3.DataRequeststruct.{:error, request_error}otherwise, whererequest_erroris aIIIFImagePlug.V3.RequestErrorstruct.
Example
def data_request(identifier) do
MyApp.ContextModule.get_image_path(identifier)
|> case do
{:ok, path} ->
{
:ok,
%IIIFImagePlug.V3.DataRequest{
path: path,
response_headers: [
{"cache-control", "public, max-age=31536000, immutable"}
]
}
}
{:error, :not_found} ->
{
:error,
%IIIFImagePlug.V3.RequestError{
status_code: 404,
msg: :not_found
}
}
end
end
@callback host() :: String.t() | nil
Optional callback function to override the :host evaluated from the Plug.Conn, useful if your Elixir app runs behind a proxy.
Example
def host(), do: "images.example.org"
@callback info_request(identifier :: String.t()) :: {:ok, IIIFImagePlug.V3.InfoRequest.t()} | {:error, IIIFImagePlug.V3.RequestError.t()}
Required callback function invoked on information requests (info.json), that maps the given identifier to an
image file.
Returns
{:ok, info_request}on success, whereinfo_requestis aIIIFImagePlug.V3.InfoRequeststruct.{:error, request_error}otherwise, whererequest_erroris aIIIFImagePlug.V3.RequestErrorstruct.
Example
def info_request(identifier) do
MyApp.ContextModule.get_image_metadata(identifier)
|> case do
%{path: path, rights_statement: rights} ->
{
:ok,
%IIIFImagePlug.V3.InfoRequest{
path: path,
rights: rights
}
}
{:error, :not_found} ->
{
:error,
%IIIFImagePlug.V3.RequestError{
status_code: 404,
msg: :not_found
}
}
end
end
@callback port() :: pos_integer() | nil
Optional callback function to override the :port evaluated from the Plug.Conn, useful if your Elixir app runs behind a proxy.
Example
def port(), do: 1337
@callback scheme() :: String.t() | nil
Optional callback function to override the :scheme ("http" or "https") evaluated from the Plug.Conn, useful if your Elixir app runs behind a
proxy.
Example
def scheme(), do: "https"
@callback send_error( conn :: Plug.Conn.t(), status_code :: number(), msg :: atom() ) :: Plug.Conn.t()
Optional callback function that lets you override the default plug error response.
Examples
Default implementation
The default response for all errors is defined as follows:
def send_error(conn, status_code, msg) do
conn
|> Plug.Conn.put_resp_content_type("application/json")
|> Plug.Conn.send_resp(
status_code,
Jason.encode!(%{error: msg})
)
endRewriting 404 for data requests to serve a fallback image
You can pattern match on specific conn, status_code or msg to overwrite specific cases.
One use case might be sending your own placeholder image instead of the JSON for failed data requests.
First customize your data_request/1 implementation with a specific message (you do not want
to return an image on a failed info.json request):
def data_request(identifier) do
MyApp.ContextModule.get_image_path(identifier)
|> case do
{:ok, path} ->
(...)
{:error, :not_found} ->
{
:error,
%IIIFImagePlug.V3.RequestError{
status_code: 404,
msg: :data_request_not_found
}
}
end
endThen add a custom send_error/3 that picks up on the status code and message you defined:
def send_error(conn, 404, :data_request_not_found) do
Plug.Conn.send_file(conn, 404, "#{Application.app_dir(:my_app)}/images/not_found.webp")
endFor all errors that do not match the pattern, the plug will be falling back to the default implementation shown above.
Rewriting errors generated by the plug
This also works for errors the plug generates interally:
def send_error(conn, 400, :invalid_rotation) do
requested_rotation = MyApp.extract_iiif_parameter(conn, :rotation)
conn
|> Plug.Conn.put_resp_content_type("application/json")
|> Plug.Conn.send_resp(
status_code,
Jason.encode!(%{error: "Your rotation parameter '#{requested_rotation}' is invalid!"})
)
end