Skip to content

Latest commit

 

History

History
236 lines (189 loc) · 9.02 KB

File metadata and controls

236 lines (189 loc) · 9.02 KB

OGC API - Tiles

MARS serves rendered raster tiles over both WMTS 1.0.0 and OGC API - Tiles 1.0 (Map Tiles conformance class). Both surfaces share the same render pipeline; only the wire shape differs. This document covers the OGC API - Tiles surface: how to enable it, what it advertises, how it caches, and how it errors.

WMTS and OGC API - Tiles coexist indefinitely. Operators can expose either or both.

Enabling

Add an interfaces.ogc_tiles block to the service config. Fields and defaults match the schema in mars-config (crates/support/mars-config/src/model/interfaces.rs, OgcTilesConfig).

interfaces:
  ogc_tiles:
    enabled: true
    # tile matrix sets to expose. names must resolve in cfg.tile_matrix_sets.
    tile_matrix_sets:
      - WebMercatorQuad
      - WorldCRS84Quad
    # MIME formats offered. order is not significant; clients select via `f=`.
    formats:
      - image/png
      - image/jpeg
      - image/webp
    # format used when a request omits `f=`. must also appear in `formats`.
    default_format: image/png
    # when true and `f=` is omitted, negotiate image/webp if the Accept header
    # advertises it and webp is in `formats`. honours `default_format` as the
    # fallback.
    prefer_webp_when_accepted: true
    # Cache-Control max-age on tile responses. seconds.
    tile_cache_max_age_seconds: 3600
    # Cache-Control max-age on metadata responses. seconds.
    metadata_cache_max_age_seconds: 300

The block is optional. Omit it (or set enabled: false) and the /ogc/tiles/ routes return 404.

Endpoints

All paths are JSON unless noted. The URL prefix /ogc/ namespaces future OGC API surfaces (Features, Maps, Styles, Coverages); only Tiles is implemented today.

Method Path Returns
GET /ogc/tiles 308 redirect to /ogc/tiles/
GET /ogc/tiles/ Landing page with link relations
GET /ogc/tiles/conformance Conformance declaration
GET /ogc/tiles/api OpenAPI 3.0 document (application/vnd.oai.openapi+json;version=3.0)
GET /ogc/tiles/collections Collections list (one per permitted layer)
GET /ogc/tiles/collections/{collectionId} Collection metadata
GET /ogc/tiles/collections/{collectionId}/map/tiles Tilesets list for the collection
GET /ogc/tiles/collections/{collectionId}/map/tiles/{tileMatrixSetId} Tileset metadata
GET /ogc/tiles/collections/{collectionId}/map/tiles/{tileMatrixSetId}/{tileMatrix}/{tileRow}/{tileCol} Rendered tile (PNG/JPEG/WebP)
GET /ogc/tiles/tileMatrixSets TMS catalog
GET /ogc/tiles/tileMatrixSets/{tileMatrixSetId} TMS document (TMS 2.0 JSON)

The tile URL template {tileMatrix}/{tileRow}/{tileCol} is fixed by the OGC API - Tiles 1.0 spec. There is no XYZ alias.

Tile format selection: append ?f=<ext> where <ext> is one of png, jpeg, webp (subject to the configured formats list). When f= is omitted, the edge selects WebP if prefer_webp_when_accepted is true and the Accept header advertises it, otherwise default_format, otherwise the first entry in formats.

Conformance classes

GET /ogc/tiles/conformance advertises the URIs MARS satisfies. The authoritative list lives in crates/interfaces/mars-ogc-tiles/src/dto/conformance.rs (CONFORMANCE_URIS). At the time of writing:

  • http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/core
  • http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/landing-page
  • http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/json
  • http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/oas30
  • http://www.opengis.net/spec/ogcapi-common-2/1.0/conf/collections
  • http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/core
  • http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/tileset
  • http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/tilesets-list
  • http://www.opengis.net/spec/ogcapi-tiles-1/1.0/conf/geodata-tilesets
  • http://www.opengis.net/spec/tms/2.0/conf/tilematrixset
  • http://www.opengis.net/spec/tms/2.0/conf/json-tilematrixset

HTTP caching

Every tile and metadata response carries ETag and Cache-Control headers, and the routes honour If-None-Match. WMTS does not currently emit either; that asymmetry is a known follow-up.

Tile ETag

Deterministic, no body hashing. Formula in crates/interfaces/mars-http/src/ogc_tiles_cache.rs (tile_etag):

ETag = blake3(
    config_etag_seed
    || current_manifest_version
    || collection || tms || z || row || col || format_mime
)[..16]

Invalidation triggers, in operator terms:

  • Manifest swap: every artifact recompile bumps the manifest version; every tile ETag changes atomically with the swap. Clients refetch on next request.

  • Config change: config_etag_seed is computed once at router construction from the interfaces.ogc_tiles block plus the TMS catalog plus per-layer policies. Any of the following invalidates every prior tile validator without needing a manifest swap:

    • toggling enabled, prefer_webp_when_accepted
    • changing tile_cache_max_age_seconds, metadata_cache_max_age_seconds
    • adding, removing, or renaming a TMS in tile_matrix_sets
    • changing the configured formats or default_format
    • changing a layer's ServiceOp::OgcTilesGetTile / OgcTilesGetCollection policy

    See compute_etag_seed in the same file for the exact inputs folded into the seed.

The seed is computed once per process start. Hot-reloading config requires a restart (same constraint as WMTS).

Metadata ETag

Strong validator over the rendered JSON body (metadata_etag in the same file). Builders are deterministic, so identical inputs produce identical bytes and identical validators across replicas.

Cache-Control

Surface Header Tunable
Tile Cache-Control: public, max-age=<tile_cache_max_age_seconds> interfaces.ogc_tiles.tile_cache_max_age_seconds (default 3600)
Metadata Cache-Control: public, max-age=<metadata_cache_max_age_seconds> interfaces.ogc_tiles.metadata_cache_max_age_seconds (default 300)

If-None-Match

If-None-Match: <etag> with an exact byte-equal match returns 304 Not Modified with the same ETag and Cache-Control headers and an empty body. If-None-Match: * always returns 304 when a representation exists. Per RFC 9110 §13.1.2.

Errors

Error responses use RFC 7807 application/problem+json. The shape is defined in crates/interfaces/mars-http/src/errors_ogc_tiles.rs (ProblemDetails).

Unknown collection (also returned when a layer denies OgcTilesGetCollection, see below):

{
  "type": "about:blank",
  "title": "Collection not found",
  "status": 404,
  "detail": "collection not found: foo"
}

Permission denied on a known collection (OgcTilesGetTile policy false):

{
  "type": "about:blank",
  "title": "Forbidden",
  "status": 403,
  "detail": "layer `foo` does not permit operation ogc_tiles_get_tile"
}

Status mapping:

Condition Status Title
Missing or invalid query/path parameter 400 Missing parameter / Invalid parameter
Collection unknown or hidden by gating 404 Collection not found
Tile matrix set unknown or hidden 404 Tile matrix set not found
Format not in formats 406 Not acceptable
OgcTilesGetTile denied on a visible collection 403 Forbidden
Runtime not ready 503 Service unavailable
Unimplemented OGC feature 501 Not implemented

Runtime-side failures (manifest unavailable, render error, etc.) share the classification table with the WMS/WMTS responders via classify_runtime_error in crates/interfaces/mars-http/src/errors.rs, so a given runtime condition maps to the same HTTP status on every surface.

Per-layer gating

Two ServiceOp values gate access:

  • ServiceOp::OgcTilesGetCollection controls whether a layer is visible at all. Default-allow; set to false to hide.
  • ServiceOp::OgcTilesGetTile controls whether tile rendering is permitted on an otherwise-visible layer. Default-allow.

The gating contract for OgcTilesGetCollection is existence-hiding: a layer with the policy denied disappears from /ogc/tiles/collections AND /ogc/tiles/collections/{collectionId} returns 404 Collection not found rather than 403. Unknown collections return the same 404. This keeps the API from confirming the existence of a layer the caller is not entitled to see.

OgcTilesGetTile is conventional: a denied tile request on a visible collection returns 403.

Configure per-layer in the service definition:

layers:
  - id: parcels
    service_ops:
      ogc_tiles_get_collection: true
      ogc_tiles_get_tile: true
  - id: internal_overlay
    service_ops:
      # hide entirely from /collections and /collections/{id}
      ogc_tiles_get_collection: false

OpenAPI

GET /ogc/tiles/api returns the OpenAPI 3.0 document for the surface, generated at compile time from the handler annotations and DTO schemas (utoipa derive in mars-ogc-tiles + handler-side #[utoipa::path(...)] in mars-http). Content type: application/vnd.oai.openapi+json;version=3.0.