Presentation API — contract¶
The post-implementation contract for iiiris's IIIF Presentation API
support (roadmap Phase 1). Operator/consumer how-to lives in
../presentation.md; this file is the durable "what
this subsystem guarantees" a re-implementation must satisfy.
What it does¶
iiiris serves IIIF Presentation manifests and collections in both 3.0 and 2.1, alongside the Image API. An identifier is resolved through the same hook + source path the Image API uses: if it names a stored JSON document it is served; if it names a directory it is auto-derived into a manifest (one canvas per image) or a collection (one member per sub-directory). A bundled viewer renders any manifest. The surface is stateless and on by default — part of the zero-config path.
Surface¶
HTTP routes¶
| Method | Path | Purpose |
|---|---|---|
| GET | /iiif/presentation/3/{id} |
3.0 manifest or collection (shape depends on what {id} resolves to) |
| GET | /iiif/presentation/2/{id} |
2.1 manifest or collection |
| GET | /view/{id} |
Bundled viewer for the manifest of {id} (Mirador default; ?viewer=uv for Universal Viewer) |
| GET | /static/viewer/{path…} |
Self-hosted viewer assets (Mirador bundle) |
| GET | /static/viewer/uv.html |
UV bootstrap shim (text/html) the ?viewer=uv iframe loads |
{id} may contain slashes. All routes are mounted only when the Presentation
API is enabled (default).
Public Go API — internal/presentation¶
Version-agnostic, pure (no I/O, no govips); the server layer supplies the
listing + probe.
- Parse / URLs:
ParsePath(v, rest) (Request, error),CanonicalID(base, v, id),ContextURI(v),IDField(v). - Serve normalisation:
NormalizeID(v, body, canonicalID) ([]byte, error)— rewrites only the top-levelid/@id. - Derive builders:
BuildManifest(v, ManifestInput),BuildCollection(v, CollectionInput)→ JSON. Inputs:ManifestInput,CollectionInput,Canvas,Member,MetadataPair. - Descriptors:
Descriptor,ChildOverride,MetadataPair;ParseSidecar(name, data),Merge(base, over),Descriptor.ChildLabel/LabelOr;SidecarNames; the optionalDescriberhook capability. - Conformance:
Validate(v, body) ([]Problem, error),Problem.
Server wiring — server.Deps¶
ManifestCache cache.InfoCache · PresentationEnabled bool · ViewerDefault string (mirador|uv) · PresentationValidate bool.
Config¶
presentation:
enabled: true # default true; false = image-only server
default_viewer: mirador # mirador (self-hosted) | uv (CDN)
validate: false # warn-only structural conformance checks
caches:
manifest: { backend: heap, max_bytes: 16777216 } # dedicated slot
All fields are optional; defaults keep the surface working with no config.
On-disk format — sidecar descriptor¶
A manifest.yaml / manifest.yml / manifest.json in a derived directory
(looked up in that order):
label: <string>
metadata:
- { label: <string>, value: <string> }
canvases:
<filename>: { label: <string> } # per-child label override
Contracts¶
- Default-on, stateless, zero-config. The Presentation routes mount unless
presentation.enabled: false; nothing underpresentation:is required for the default path. No new state is introduced (derived docs are cached, not stored). - Resolution is the Image API's.
hook.Resolve(id) → (backend, key)thensource.Open(key). A child image identifier isdir + "/" + filename, so the same hook maps it consistently. - Document → serve as-is. Only the top-level
id(@idin 2.1) is rewritten to the canonical/iiif/presentation/{v}/{id}URL; nested values are byte-preserved. iiiris never rewrites or transcodes a stored document beyond that. - Directory → derive. Images → a Manifest (one canvas per image); sub-directories → a Collection (one member per sub-directory, classified Manifest-vs-Collection one level deep, members resolved lazily on their own request). Non-image files are skipped; a directory with neither is 404.
- Canvas dimensions come from a header-only
image.Probe— no full decode.govipsstays single-consumer (internal/image); the Presentation code calls onlyimage.Probe. - Each derived canvas paints an Image API service on this same server,
with strict version pairing: a v3 manifest links an
ImageService3at/iiif/3/{imgid}; a v2 manifest anImageService2at/iiif/2/{imgid}(profilelevel2.json). Plus a confined-size thumbnail. - Derive override precedence: conventions < sidecar < hook. Filename/path
conventions are the always-present baseline; a directory sidecar overrides
them; a
Describerhook is authoritative. A malformed override is logged and ignored — derivation never fails because an override is bad. - No cross-version conversion. A stored 3.0 manifest is served as-is under
/3/; it is not transcoded to 2.1 for/2/(and vice versa). Derivation emits the route's version from the source directory. - Dedicated manifest cache slot. Derived/served documents cache via
ManifestCache(thecache.InfoCacheinterface, built bycache.BuildInfofromcaches.manifest), keyed by host + version + identifier — a separate slot from InfoCache. Served stored documents additionally carry HTTP cache semantics (ETag, conditional GET → 304) andapplication/ld+jsoncontent negotiation. - Validation is warn-only. With
presentation.validate: true, served and derived documents are checked against the version's required structure and problems are logged at WARN; documents are never rejected. Every document iiiris derives is structurally valid — enforced by the test suite and theiiif-presentation-validateCI stage (a live-server harness reusingValidate). - Viewer.
/view/{id}renders Mirador by default — self-hosted viago:embed, served under/static/viewer/, referenced root-relative so it loads over the page's own scheme (offline, no mixed content).?viewer=uv(ordefault_viewer: uv) serves an iiiris-hosteduv.htmlshim (text/html) that loads Universal Viewer from a version-pinned CDN and reads the manifest from the URL hash. - Scheme correctness is the operator's job. The manifest URL and the
image-service URLs within it are built from the request scheme/host
(
publicBase); behind a TLS-terminating proxy the proxy must sendX-Forwarded-Proto: https(andX-Forwarded-Host), or a browser blocks thehttp://URLs as mixed content.
Out of scope¶
- Manifest author/edit (write APIs) — stateful; roadmap Phase 3 / 1.x.
- Cross-version conversion of stored documents — see contracts.
- Annotation content / Content Search — roadmap Phase 3.
- Presentation versions other than 3.0 / 2.1.
- Self-hosting Universal Viewer — UV 4.x's ~10–21 MB runtime asset tree is loaded from a CDN; only Mirador (a single self-contained bundle) is embedded.
- Deriving the source root itself — a Presentation identifier must name a sub-path; the empty/root identifier is not derivable.