From 9df17317c45c439088beb6f88cea043d345fd8e9 Mon Sep 17 00:00:00 2001 From: Vincent Sarago Date: Thu, 21 Mar 2024 10:15:14 +0100 Subject: [PATCH] add colormap endpoints (#796) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bump version: 0.17.0 → 0.17.1 * add colormap endpoints * fix orientation * update height/width descriptions * remove hex options and handle different cmap types * update from main * fix typo * support discrete cmap * handle sequence cmap * add tests * update docs * colormaps -> colorMaps * update changelog --- .bumpversion.cfg | 4 +- CHANGES.md | 6 + docs/mkdocs.yml | 4 +- ...er_factories.md => endpoints_factories.md} | 199 ++++++++++++++---- docs/src/endpoints/algorithms.md | 116 ++++++++++ docs/src/endpoints/colormaps.md | 96 +++++++++ docs/src/endpoints/tms.md | 14 +- docs/src/intro.md | 6 +- .../application/titiler/application/main.py | 10 + src/titiler/core/tests/test_factories.py | 131 ++++++++++++ src/titiler/core/titiler/core/factory.py | 192 ++++++++++++++++- src/titiler/core/titiler/core/models/OGC.py | 80 ++++++- .../core/titiler/core/models/responses.py | 9 + .../core/titiler/core/resources/enums.py | 8 +- 14 files changed, 815 insertions(+), 60 deletions(-) rename docs/src/advanced/{tiler_factories.md => endpoints_factories.md} (68%) create mode 100644 docs/src/endpoints/algorithms.md create mode 100644 docs/src/endpoints/colormaps.md diff --git a/.bumpversion.cfg b/.bumpversion.cfg index ac25f52f3..0597775ba 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -3,10 +3,10 @@ current_version = 0.17.3 commit = True tag = True tag_name = {new_version} -parse = +parse = (?P\d+)\.(?P\d+)\.(?P\d+) ((?P
a|b|rc)(?P\d+))?
-serialize = 
+serialize =
 	{major}.{minor}.{patch}{pre}{prenum}
 	{major}.{minor}.{patch}
 
diff --git a/CHANGES.md b/CHANGES.md
index fd0189dae..bc3359c7d 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,11 @@
 # Release Notes
 
+## Unreleased
+
+### titiler.core
+
+* Add `ColorMapFactory` to create colorMap metadata endpoints (https://github.com/developmentseed/titiler/pull/796)
+
 ## 0.17.3 (2024-03-21)
 
 ### titiler.application
diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml
index b662f4a1c..228db2bae 100644
--- a/docs/mkdocs.yml
+++ b/docs/mkdocs.yml
@@ -28,7 +28,7 @@ nav:
     - Output data format: "output_format.md"
 
   - Advanced User Guide:
-      - Tiler Factories: "advanced/tiler_factories.md"
+      - Endpoints Factories: "advanced/endpoints_factories.md"
       - Dependencies: "advanced/dependencies.md"
       - Customization: "advanced/customization.md"
       - Performance Tuning: "advanced/performance_tuning.md"
@@ -42,6 +42,8 @@ nav:
     - /stac: "endpoints/stac.md"
     - /mosaicjson: "endpoints/mosaic.md"
     - /tileMatrixSets: "endpoints/tms.md"
+    - /algorithms: "endpoints/algorithms.md"
+    - /colormaps: "endpoints/colormaps.md"
 
   - Examples:
     - Create dynamic tilers with TiTiler:
diff --git a/docs/src/advanced/tiler_factories.md b/docs/src/advanced/endpoints_factories.md
similarity index 68%
rename from docs/src/advanced/tiler_factories.md
rename to docs/src/advanced/endpoints_factories.md
index 129a23ff8..451541fe4 100644
--- a/docs/src/advanced/tiler_factories.md
+++ b/docs/src/advanced/endpoints_factories.md
@@ -1,9 +1,18 @@
 
-Tiler factories are helper functions that let users create a FastAPI router (`fastapi.APIRouter`) with a minimal set of endpoints.
+TiTiler's endpoints factories are helper functions that let users create a FastAPI *router* (`fastapi.APIRouter`) with a minimal set of endpoints.
+
+!!! Important
+
+    Most of `tiler` **Factories** are built around [`rio_tiler.io.BaseReader`](https://cogeotiff.github.io/rio-tiler/advanced/custom_readers/), which defines basic methods to access datasets (e.g COG or STAC). The default reader is `Reader` for `TilerFactory` and `MosaicBackend` for `MosaicTilerFactory`.
+
+    Factories classes use [dependencies injection](dependencies.md) to define most of the endpoint options.
 
-### BaseTilerFactory
 
-All **Factories** are built from an [abstract based class](https://docs.python.org/3/library/abc.html) which is used to define commons attributes and utility functions shared between all factories.
+## BaseTilerFactory
+
+class: `titiler.core.factory.BaseTilerFactory`
+
+Most **Factories** are built from this [abstract based class](https://docs.python.org/3/library/abc.html) which is used to define commons attributes and utility functions shared between all factories.
 
 #### Methods
 
@@ -23,19 +32,21 @@ All **Factories** are built from an [abstract based class](https://docs.python.o
 - **color_formula_dependency**: Dependency to define the Color Formula. Defaults to `titiler.core.dependencies.ColorFormulaParams`.
 - **colormap_dependency**: Dependency to define the Colormap options. Defaults to `titiler.core.dependencies.ColorMapParams`
 - **render_dependency**: Dependency to control output image rendering options. Defaults to `titiler.core.dependencies.ImageRenderingParams`
+- **reader_dependency**: Dependency to control options passed to the reader instance init. Defaults to `titiler.core.dependencies.DefaultDependency`
 - **environment_dependency**: Dependency to defile GDAL environment at runtime. Default to `lambda: {}`.
-
-- **supported_tms**:
-- **default_tms**: Set default `TileMatrixSet` identifier to use. Defaults to `WebMercatorQuad`.
+- **supported_tms**: List of available TileMatrixSets. Defaults to `morecantile.tms`.
+- **default_tms**: Default `TileMatrixSet` identifier to use. Defaults to `WebMercatorQuad`.
 - **router_prefix**: Set prefix to all factory's endpoint. Defaults to `""`.
 - **optional_headers**: List of `OptionalHeader` which endpoints could add (if implemented). Defaults to `[]`.
 - **route_dependencies**: Additional routes dependencies to add after routes creations. Defaults to `[]`.
 - **extension**: TiTiler extensions to register after endpoints creations. Defaults to `[]`.
-- **templates**: *Jinja2* templates to use in endpoints. Defaults to `titiler.core.factory.DEFAULT_TEMPLATES`
+- **templates**: *Jinja2* templates to use in endpoints. Defaults to `titiler.core.factory.DEFAULT_TEMPLATES`.
 
 
 ## TilerFactory
 
+class: `titiler.core.factory.TilerFactory`
+
 Factory meant to create endpoints for single dataset using [*rio-tiler*'s `Reader`](https://cogeotiff.github.io/rio-tiler/readers/#rio_tileriorasterioreader).
 
 #### Attributes
@@ -46,9 +57,9 @@ Factory meant to create endpoints for single dataset using [*rio-tiler*'s `Reade
 - **img_preview_dependency**: Dependency to define image size for `/preview` and `/statistics` endpoints. Defaults to `titiler.core.dependencies.PreviewParams`.
 - **img_part_dependency**: Dependency to define image size for `/bbox` and `/feature` endpoints. Defaults to `titiler.core.dependencies.PartFeatureParams`.
 - **tile_dependency**: Dependency to defile `buffer` and `padding` to apply at tile creation. Defaults to `titiler.core.dependencies.TileParams`.
-- **add_preview**: . Defaults to `True`
-- **add_part**: . Defaults to `True`
-- **add_viewer**: . Defaults to `True`
+- **add_preview**: . Add `/preview` endpoint to the router. Defaults to `True`.
+- **add_part**: . Add `/bbox` and `/feature` endpoints to the router. Defaults to `True`.
+- **add_viewer**: . Add `/map` endpoints to the router. Defaults to `True`.
 
 #### Endpoints
 
@@ -57,9 +68,18 @@ from fastapi import FastAPI
 
 from titiler.core.factory import TilerFactory
 
+# Create FastAPI application
 app = FastAPI()
-cog = TilerFactory()
-app.include_router(cog.router
+
+# Create router and register set of endpoints
+cog = TilerFactory(
+    add_preview=True,
+    add_part=True,
+    add_viewer=True,
+)
+
+# add router endpoint to the main application
+app.include_router(cog.router)
 ```
 
 | Method | URL                                                             | Output                                      | Description
@@ -73,19 +93,21 @@ app.include_router(cog.router
 | `GET`  | `[/{tileMatrixSetId}]/tilejson.json`                            | JSON ([TileJSON][tilejson_model])           | return a Mapbox TileJSON document
 | `GET`  | `[/{tileMatrixSetId}]/WMTSCapabilities.xml`                     | XML                                         | return OGC WMTS Get Capabilities
 | `GET`  | `/point/{lon},{lat}`                                            | JSON ([Point][point_model])                 | return pixel values from a dataset
-| `GET`  | `/preview[.{format}]`                                           | image/bin                                   | create a preview image from a dataset (**Optional**)
-| `GET`  | `/bbox/{minx},{miny},{maxx},{maxy}[/{width}x{height}].{format}` | image/bin                                   | create an image from part of a dataset (**Optional**)
-| `POST` | `/feature[/{width}x{height}][.{format}]`                           | image/bin                                   | create an image from a GeoJSON feature (**Optional**)
-| `GET`  | `/map`                                                          | HTML                                        | return a simple map viewer
-| `GET`  | `[/{tileMatrixSetId}]/map`                                      | HTML                                        | return a simple map viewer
+| `GET`  | `/preview[.{format}]`                                           | image/bin                                   | create a preview image from a dataset **Optional**
+| `GET`  | `/bbox/{minx},{miny},{maxx},{maxy}[/{width}x{height}].{format}` | image/bin                                   | create an image from part of a dataset **Optional**
+| `POST` | `/feature[/{width}x{height}][.{format}]`                        | image/bin                                   | create an image from a GeoJSON feature **Optional**
+| `GET`  | `[/{tileMatrixSetId}]/map`                                      | HTML                                        | return a simple map viewer **Optional**
 
 
 ## MultiBaseTilerFactory
 
-Custom `TilerFactory` to be used with [`rio_tiler.io.MultiBaseReader`](http://127.0.0.1:8000/titiler/advanced/tiler_factories/#titilercorefactorymultibasetilerfactory) type readers (e.g `rio_tiler.io.STACReader`).
+class: `titiler.core.factory.MultiBaseTilerFactory`
+
+Custom `TilerFactory` to be used with [`rio_tiler.io.MultiBaseReader`](https://cogeotiff.github.io/rio-tiler/advanced/custom_readers/#multibasereader) type readers (e.g [`rio_tiler.io.STACReader`](https://cogeotiff.github.io/rio-tiler/readers/#rio_tileriostacstacreader)).
 
 #### Attributes
 
+- **reader**: `MultiBase` Dataset Reader **required**.
 - **layer_dependency**: Dependency to define assets or expression. Defaults to `titiler.core.dependencies.AssetsBidxExprParams`.
 - **assets_dependency**: Dependency to define assets to be used. Defaults to `titiler.core.dependencies.AssetsParams`.
 
@@ -93,14 +115,14 @@ Custom `TilerFactory` to be used with [`rio_tiler.io.MultiBaseReader`](http://12
 
 ```python
 from fastapi import FastAPI
-# rio_tiler.io.STACReader is a MultiBaseReader
-from rio_tiler.io import STACReader
+
+from rio_tiler.io import STACReader  # STACReader is a MultiBaseReader
 
 from titiler.core.factory import MultiBaseTilerFactory
 
 app = FastAPI()
 stac = MultiBaseTilerFactory(reader=STACReader)
-app.include_router(stac.router])
+app.include_router(stac.router)
 ```
 
 | Method | URL                                                             | Output                                           | Description
@@ -116,17 +138,21 @@ app.include_router(stac.router])
 | `GET`  | `/[{tileMatrixSetId}]/tilejson.json`                            | JSON ([TileJSON][tilejson_model])                | return a Mapbox TileJSON document
 | `GET`  | `/{tileMatrixSetId}/WMTSCapabilities.xml`                       | XML                                              | return OGC WMTS Get Capabilities
 | `GET`  | `/point/{lon},{lat}`                                            | JSON ([Point][multipoint_model])                 | return pixel values from assets
-| `GET`  | `/preview[.{format}]`                                           | image/bin                                        | create a preview image from assets (**Optional**)
-| `GET`  | `/bbox/{minx},{miny},{maxx},{maxy}[/{width}x{height}].{format}` | image/bin                                        | create an image from part of assets (**Optional**)
-| `POST` | `/feature[/{width}x{height}][.{format}]`                           | image/bin                                        | create an image from a geojson feature intersecting assets (**Optional**)
-| `GET`  | `[/{tileMatrixSetId}]/map`                                      | HTML                                             | return a simple map viewer
+| `GET`  | `/preview[.{format}]`                                           | image/bin                                        | create a preview image from assets **Optional**
+| `GET`  | `/bbox/{minx},{miny},{maxx},{maxy}[/{width}x{height}].{format}` | image/bin                                        | create an image from part of assets **Optional**
+| `POST` | `/feature[/{width}x{height}][.{format}]`                        | image/bin                                        | create an image from a geojson feature intersecting assets **Optional**
+| `GET`  | `[/{tileMatrixSetId}]/map`                                      | HTML                                             | return a simple map viewer **Optional**
+
 
 ## MultiBandTilerFactory
 
-Custom `TilerFactory` to be used with [`rio_tiler.io.MultiBandReader`](https://cogeotiff.github.io/rio-tiler/advanced/custom_readers/#multibasereader) type readers.
+class: `titiler.core.factory.MultiBandTilerFactory`
+
+Custom `TilerFactory` to be used with [`rio_tiler.io.MultiBandReader`](https://cogeotiff.github.io/rio-tiler/advanced/custom_readers/#multibandsreader) type readers.
 
 #### Attributes
 
+- **reader**: `MultiBands` Dataset Reader **required**.
 - **layer_dependency**: Dependency to define assets or expression. Defaults to `titiler.core.dependencies.BandsExprParams`.
 - **bands_dependency**: Dependency to define bands to be used. Defaults to `titiler.core.dependencies.BandsParams`.
 
@@ -134,8 +160,9 @@ Custom `TilerFactory` to be used with [`rio_tiler.io.MultiBandReader`](https://c
 
 ```python
 from fastapi import FastAPI, Query
-# rio_tiler_pds.landsat.aws.LandsatC2Reader is a MultiBandReader
-from rio_tiler_pds.landsat.aws import LandsatC2Reader
+
+
+from rio_tiler_pds.landsat.aws import LandsatC2Reader  # LandsatC2Reader is a MultiBandReader
 from titiler.core.factory import MultiBandTilerFactory
 
 
@@ -166,20 +193,28 @@ app.include_router(landsat.router)
 | `GET`  | `/[{tileMatrixSetId}]/tilejson.json`                            | JSON ([TileJSON][tilejson_model])            | return a Mapbox TileJSON document
 | `GET`  | `/{tileMatrixSetId}/WMTSCapabilities.xml`                       | XML                                          | return OGC WMTS Get Capabilities
 | `GET`  | `/point/{lon},{lat}`                                            | JSON ([Point][point_model])                  | return pixel value from a dataset
-| `GET`  | `/preview[.{format}]`                                           | image/bin                                    | create a preview image from a dataset
-| `GET`  | `/bbox/{minx},{miny},{maxx},{maxy}[/{width}x{height}].{format}` | image/bin                                    | create an image from part of a dataset
-| `POST` | `/feature[/{width}x{height}][.{format}]`                           | image/bin                                    | create an image from a geojson feature
-| `GET`  | `[/{tileMatrixSetId}]/map`                                      | HTML                                         | return a simple map viewer
+| `GET`  | `/preview[.{format}]`                                           | image/bin                                    | create a preview image from a dataset **Optional**
+| `GET`  | `/bbox/{minx},{miny},{maxx},{maxy}[/{width}x{height}].{format}` | image/bin                                    | create an image from part of a dataset **Optional**
+| `POST` | `/feature[/{width}x{height}][.{format}]`                        | image/bin                                    | create an image from a geojson feature **Optional**
+| `GET`  | `[/{tileMatrixSetId}]/map`                                      | HTML                                         | return a simple map viewer **Optional**
+
 
 ## MosaicTilerFactory
 
+class: `titiler.mosaic.factory.MosaicTilerFactory`
 
-In `titiler.mosaic.factory`, custom `TilerFactory`
+Endpoints factory for mosaics, built on top of [MosaicJSON](https://github.com/developmentseed/mosaicjson-spec).
 
 #### Attributes
 
-- **layer_dependency**: Dependency to define assets or expression. Defaults to `titiler.core.dependencies.BandsExprParams`.
-- **bands_dependency**: Dependency to define bands to be used. Defaults to `titiler.core.dependencies.BandsParams`.
+- **reader**: `BaseBackend` Mosaic Reader **required**.
+- **dataset_reader**: Dataset Reader. Defaults to `rio_tiler.io.Reader`
+- **backend_dependency**: Dependency to control options passed to the backend instance init. Defaults to `titiler.core.dependencies.DefaultDependency`
+- **pixel_selection_dependency**: Dependency to select the `pixel_selection` method. Defaults to `titiler.mosaic.factory.PixelSelectionParams`.
+- **tile_dependency**: Dependency to defile `buffer` and `padding` to apply at tile creation. Defaults to `titiler.core.dependencies.TileParams`.
+- **supported_tms**: List of available TileMatrixSets. Defaults to `morecantile.tms`.
+- **default_tms**: Default `TileMatrixSet` identifier to use. Defaults to `WebMercatorQuad`.
+- **add_viewer**: . Add `/map` endpoints to the router. Defaults to `True`.
 
 #### Endpoints
 
@@ -196,14 +231,92 @@ In `titiler.mosaic.factory`, custom `TilerFactory`
 | `GET`  | `/{z}/{x}/{y}/assets`                                           | JSON                                               | return list of assets intersecting a XYZ tile
 | `GET`  | `/{lon},{lat}/assets`                                           | JSON                                               | return list of assets intersecting a point
 | `GET`  | `/{minx},{miny},{maxx},{maxy}/assets`                           | JSON                                               | return list of assets intersecting a bounding box
-| `GET`  | `[/{tileMatrixSetId}]/map`                                      | HTML                                               | return a simple map viewer
+| `GET`  | `[/{tileMatrixSetId}]/map`                                      | HTML                                               | return a simple map viewer **Optional**
 
 
-!!! Important
+## TMSFactory
 
-    **Factories** are built around [`rio_tiler.io.BaseReader`](https://cogeotiff.github.io/rio-tiler/advanced/custom_readers/), which defines basic methods to access datasets (e.g COG or STAC). The default reader is `Reader` for `TilerFactory` and `MosaicBackend` for `MosaicTilerFactory`.
+class: `titiler.core.factory.TMSFactory`
+
+Endpoints factory for OGC `TileMatrixSets`.
+
+#### Attributes
+
+- **supported_tms**: List of available TileMatrixSets. Defaults to `morecantile.tms`.
+
+```python
+from fastapi import FastAPI
+
+from titiler.core.factory import TMSFactory
+
+app = FastAPI()
+tms = TMSFactory()
+app.include_router(tms.router)
+```
+
+#### Endpoints
+
+| Method | URL                                   | Output                                         | Description
+| ------ | ------------------------------------- |----------------------------------------------- |--------------
+| `GET`  | `/tileMatrixSets`                     | JSON ([TileMatrixSetList][tilematrixset_list]) | retrieve the list of available tiling schemes (tile matrix sets)
+| `GET`  | `/tileMatrixSets/{tileMatrixSetId}`   | JSON ([TileMatrixSet][tilematrixset])          | retrieve the definition of the specified tiling scheme (tile matrix set)
+
+
+## AlgorithmFactory
+
+class: `titiler.core.factory.AlgorithmFactory`
+
+Endpoints factory for custom algorithms.
+
+#### Attributes
+
+- **supported_algorithm**: List of available `Algorithm`. Defaults to `titiler.core.algorithm.algorithms`.
+
+```python
+from fastapi import FastAPI
+
+from titiler.core.factory import AlgorithmFactory
+
+app = FastAPI()
+algo = AlgorithmFactory()
+app.include_router(algo.router)
+```
+
+#### Endpoints
+
+| Method | URL                          | Output                                                   | Description
+| ------ | ---------------------------- |--------------------------------------------------------- |--------------
+| `GET`  | `/algorithms`                | JSON (Dict of [Algorithm Metadata][algorithm_metadata])            | retrieve the list of available Algorithms
+| `GET`  | `/algorithms/{algorithmId}`  | JSON ([Algorithm Metadata][algorithm_metadata])                    | retrieve the metadata of the specified algorithm.
+
+
+## ColorMapFactory
+
+class: `titiler.core.factory.ColorMapFactory`
+
+Endpoints factory for colorMaps metadata.
+
+#### Attributes
+
+- **supported_colormaps**: List of available `ColorMaps`. Defaults to `rio_tiler.colormap.cmap`.
+
+```python
+from fastapi import FastAPI
+
+from titiler.core.factory import ColorMapFactory
+
+app = FastAPI()
+colormap = ColorMapFactory()
+app.include_router(colormap.router)
+```
+
+#### Endpoints
+
+| Method | URL                          | Output                                | Description
+| ------ | ---------------------------- |-------------------------------------- |--------------
+| `GET`  | `/colorMaps`                 | JSON ([colorMapList][colormap_list])  | retrieve the list of available colorMaps
+| `GET`  | `/colorMaps/{colorMapId}`    | JSON ([colorMap][colormap])           | retrieve the metadata or image of the specified colorMap.
 
-    Factories classes use [dependencies injection](dependencies.md) to define most of the endpoint options.
 
 
 [bounds_model]: https://github.com/cogeotiff/rio-tiler/blob/9aaa88000399ee8d36e71d176f67b6ea3ec53f2d/rio_tiler/models.py#L43-L46
@@ -224,3 +337,11 @@ In `titiler.mosaic.factory`, custom `TilerFactory`
 [mosaic_geojson_info_model]: https://github.com/developmentseed/titiler/blob/2bd1b159a9cf0932ad14e9eabf1e4e66498adbdc/src/titiler/mosaic/titiler/mosaic/factory.py#L130
 [mosaic_model]: https://github.com/developmentseed/cogeo-mosaic/blob/1dc3c873472c8cf7634ad893b9cdc40105ca3874/cogeo_mosaic/mosaic.py#L55-L72
 [mosaic_point]: https://github.com/developmentseed/titiler/blob/2bd1b159a9cf0932ad14e9eabf1e4e66498adbdc/src/titiler/mosaic/titiler/mosaic/models/responses.py#L8-L17
+
+[tilematrixset_list]: https://github.com/developmentseed/titiler/blob/ffd67af34c2807a6e1447817f943446a58441ed8/src/titiler/core/titiler/core/models/OGC.py#L33-L40
+[tilematrixset]: https://github.com/developmentseed/morecantile/blob/eec54326ce2b134cfbc03dd69a3e2938e4109101/morecantile/models.py#L399-L490
+
+[algorithm_metadata]: https://github.com/developmentseed/titiler/blob/ffd67af34c2807a6e1447817f943446a58441ed8/src/titiler/core/titiler/core/algorithm/base.py#L32-L40
+
+[colormap_list]: https://github.com/developmentseed/titiler/blob/535304fd7e1b0bfbb791bdec8cbfb6e78b4a6eb5/src/titiler/core/titiler/core/models/responses.py#L51-L55
+[colormap]: https://github.com/cogeotiff/rio-tiler/blob/6343b571a367ef63a10d6807e3d907c3283ebb20/rio_tiler/types.py#L24-L27
diff --git a/docs/src/endpoints/algorithms.md b/docs/src/endpoints/algorithms.md
new file mode 100644
index 000000000..58e375eee
--- /dev/null
+++ b/docs/src/endpoints/algorithms.md
@@ -0,0 +1,116 @@
+In addition to the `/cog`, `/stac` and `/mosaicjson` endpoints, the `titiler.application` package FastAPI application commes with additional metadata endpoints.
+
+# Algorithms
+
+## API
+
+| Method | URL                          | Output          | Description
+| ------ | ---------------------------- |---------------- |--------------
+| `GET`  | `/algorithms`                | JSON            | retrieve the list of available Algorithms
+| `GET`  | `/algorithms/{algorithmId}`  | JSON            | retrieve the metadata of the specified algorithm.
+
+## Description
+
+
+### List Algorithm
+
+`:endpoint:/algorithm` - Get the list of supported TileMatrixSet
+
+```bash
+$ curl https://myendpoint/algorithms | jq
+
+{
+  "hillshade": {
+    "title": "Hillshade",
+    "description": "Create hillshade from DEM dataset.",
+    "inputs": {
+      "nbands": 1
+    },
+    "outputs": {
+      "nbands": 1,
+      "dtype": "uint8",
+      "min": null,
+      "max": null
+    },
+    "parameters": {
+      "azimuth": {
+        "default": 90,
+        "maximum": 360,
+        "minimum": 0,
+        "title": "Azimuth",
+        "type": "integer"
+      },
+      "angle_altitude": {
+        "default": 90.0,
+        "maximum": 90.0,
+        "minimum": -90.0,
+        "title": "Angle Altitude",
+        "type": "number"
+      },
+      "buffer": {
+        "default": 3,
+        "maximum": 99,
+        "minimum": 0,
+        "title": "Buffer",
+        "type": "integer"
+      }
+    }
+  },
+  ...
+}
+```
+
+### Get Algorithm info
+
+`:endpoint:/algorithms/{algorithmId}` - Get the algorithm metadata
+
+- PathParams:
+    - **algorithmId**: algorithm name
+
+```bash
+$ curl http://127.0.0.1:8000/algorithms/contours | jq
+
+{
+  "title": "Contours",
+  "description": "Create contours from DEM dataset.",
+  "inputs": {
+    "nbands": 1
+  },
+  "outputs": {
+    "nbands": 3,
+    "dtype": "uint8",
+    "min": null,
+    "max": null
+  },
+  "parameters": {
+    "increment": {
+      "default": 35,
+      "maximum": 999,
+      "minimum": 0,
+      "title": "Increment",
+      "type": "integer"
+    },
+    "thickness": {
+      "default": 1,
+      "maximum": 10,
+      "minimum": 0,
+      "title": "Thickness",
+      "type": "integer"
+    },
+    "minz": {
+      "default": -12000,
+      "maximum": 99999,
+      "minimum": -99999,
+      "title": "Minz",
+      "type": "integer"
+    },
+    "maxz": {
+      "default": 8000,
+      "maximum": 99999,
+      "minimum": -99999,
+      "title": "Maxz",
+      "type": "integer"
+    }
+  }
+}
+```
diff --git a/docs/src/endpoints/colormaps.md b/docs/src/endpoints/colormaps.md
new file mode 100644
index 000000000..8ad4f10db
--- /dev/null
+++ b/docs/src/endpoints/colormaps.md
@@ -0,0 +1,96 @@
+In addition to the `/cog`, `/stac` and `/mosaicjson` endpoints, the `titiler.application` package FastAPI application commes with additional metadata endpoints.
+
+# Algorithms
+
+## API
+
+| Method | URL                          | Output | Description
+| ------ | ---------------------------- |--------|--------------
+| `GET`  | `/colorMaps`                 | JSON   | retrieve the list of available colorMaps
+| `GET`  | `/colorMaps/{colorMapId}`    | JSON   | retrieve the metadata or image of the specified colorMap.
+
+## Description
+
+
+### List colormaps
+
+`:endpoint:/colorMaps` - Get the list of supported ColorMaps
+
+```bash
+$ curl https://myendpoint/colorMaps | jq
+
+{
+  "colorMaps": [
+    "dense_r",
+    "delta",
+    ...
+  ],
+  "links": [
+    {
+      "href": "http://myendpoint/colorMaps",
+      "rel": "self",
+      "type": "application/json",
+      "title": "List of available colormaps"
+    },
+    {
+      "href": "http://myendpoint/colorMaps/{colorMapId}",
+      "rel": "data",
+      "type": "application/json",
+      "templated": true,
+      "title": "Retrieve colormap metadata"
+    },
+    {
+      "href": "http://myendpoint/colorMaps/{colorMapId}?format=png",
+      "rel": "data",
+      "type": "image/png",
+      "templated": true,
+      "title": "Retrieve colormap as image"
+    }
+  ]
+}
+```
+
+### Get ColorMap metadata or as image
+
+`:endpoint:/colorMaps/{colorMapId}` - Get the ColorMap metadata or image
+
+- PathParams:
+    - **colorMapId**: colormap name
+
+- QueryParams:
+    - **format** (str): output image format (PNG/JPEG...). Defaults to JSON output.
+    - **orientation** (["vertical", "horizontal"]): image orientation. Defaults to `horizontal`.
+    - **height** (int): output image height. Default to 20px for horizontal or 256px for vertical.
+    - **width** (int): output image width. Defaults to 256px for horizontal or 20px for vertical.
+
+```bash
+$ curl http://myendpoint/colorMaps/viridis | jq
+
+{
+  "0": [
+    68,
+    1,
+    84,
+    255
+  ],
+  ...
+  "255": [
+    253,
+    231,
+    36,
+    255
+  ]
+}
+```
+
+```
+curl http://myendpoint/colorMaps/viridis?format=png
+```
+
+```
+curl http://myendpoint/colorMaps/viridis?format=png&orientation=vertical
+```
+
+```
+curl http://myendpoint/colorMaps/viridis?format=png&orientation=vertical&width=100&height=1000
+```
diff --git a/docs/src/endpoints/tms.md b/docs/src/endpoints/tms.md
index aa01b3c01..3a634b682 100644
--- a/docs/src/endpoints/tms.md
+++ b/docs/src/endpoints/tms.md
@@ -1,17 +1,7 @@
-The `titiler.application` package comes with a full FastAPI application with COG, STAC and MosaicJSON supports.
 
-# TileMatrixSets
-
-The `tms` router extend the default `titiler.core.factory.TMSFactory`, adding some custom TileMatrixSets.
-
-```python
-from fastapi import FastAPI
-from titiler.application.routers.tms import tms
-
-app = FastAPI()
-app.include_router(tms.router, tags=["TileMatrixSets"])
-```
+In addition to the `/cog`, `/stac` and `/mosaicjson` endpoints, the `titiler.application` package FastAPI application comes with additional metadata endpoints.
 
+# TileMatrixSets
 
 ## API
 
diff --git a/docs/src/intro.md b/docs/src/intro.md
index 3d3a785cb..685f18acd 100644
--- a/docs/src/intro.md
+++ b/docs/src/intro.md
@@ -27,7 +27,9 @@ See default endpoints documentation pages:
 * [`/cog` - Cloud Optimized GeoTIFF](endpoints/cog.md)
 * [`/mosaicjson` - MosaicJSON](endpoints/mosaic.md)
 * [`/stac` - Spatio Temporal Asset Catalog](endpoints/stac.md)
-* [`/tms` - TileMatrixSets](endpoints/tms.md)
+* [`/tileMatrixSets` - Tiling Schemes](endpoints/tms.md)
+* [`/algorithms` - Algorithms](endpoints/algorithms.md)
+* [`/colorMaps` - ColorMaps](endpoints/colormaps.md)
 
 #### Settings
 
@@ -47,7 +49,7 @@ The default application can be customized using environment variables defined in
 
 ## Customized, minimal app
 
-`TiTiler` has been developed so users can build their own app using only the portions they need. Using [TilerFactories](advanced/tiler_factories.md), users can create a fully customized application with only the endpoints needed.
+`TiTiler` has been developed so users can build their own application with only the endpoints they need. Using [Factories](advanced/endpoints_factories.md), users can create a fully customized application with only a defined set of endpoints.
 
 When building a custom application, you may wish to only install the `core` and/or `mosaic` modules. To install these from PyPI:
 
diff --git a/src/titiler/application/titiler/application/main.py b/src/titiler/application/titiler/application/main.py
index 522088c63..a8acafb15 100644
--- a/src/titiler/application/titiler/application/main.py
+++ b/src/titiler/application/titiler/application/main.py
@@ -18,6 +18,7 @@
 from titiler.core.errors import DEFAULT_STATUS_CODES, add_exception_handlers
 from titiler.core.factory import (
     AlgorithmFactory,
+    ColorMapFactory,
     MultiBaseTilerFactory,
     TilerFactory,
     TMSFactory,
@@ -155,6 +156,15 @@ def validate_access_token(access_token: str = Security(api_key_query)):
     tags=["Algorithms"],
 )
 
+###############################################################################
+# Colormaps endpoints
+cmaps = ColorMapFactory()
+app.include_router(
+    cmaps.router,
+    tags=["ColorMaps"],
+)
+
+
 add_exception_handlers(app, DEFAULT_STATUS_CODES)
 add_exception_handlers(app, MOSAIC_STATUS_CODES)
 
diff --git a/src/titiler/core/tests/test_factories.py b/src/titiler/core/tests/test_factories.py
index 9b8ac2c4b..a4df4eb44 100644
--- a/src/titiler/core/tests/test_factories.py
+++ b/src/titiler/core/tests/test_factories.py
@@ -20,6 +20,7 @@
 from morecantile.defaults import TileMatrixSets
 from rasterio.crs import CRS
 from rasterio.io import MemoryFile
+from rio_tiler.colormap import cmap as default_cmap
 from rio_tiler.errors import NoOverviewWarning
 from rio_tiler.io import BaseReader, MultiBandReader, Reader, STACReader
 from starlette.requests import Request
@@ -30,6 +31,7 @@
 from titiler.core.factory import (
     AlgorithmFactory,
     BaseTilerFactory,
+    ColorMapFactory,
     MultiBandTilerFactory,
     MultiBaseTilerFactory,
     TilerFactory,
@@ -1761,3 +1763,132 @@ def custom_color_formula_params() -> Optional[str]:
         assert response.headers["content-type"] == "application/x-binary"
         numpy.load(BytesIO(response.content))
         assert npy_tile.shape == (2, 256, 256)  # mask + data
+
+
+def test_colormap_factory():
+    """Test ColorMapFactory endpoint."""
+    # Register custom colormaps
+    cmaps = default_cmap.register(
+        {
+            "cust": {0: (0, 0, 0, 255), 1: (255, 0, 0, 255), 255: (255, 255, 0, 255)},
+            "negative": {
+                -100: (0, 0, 0, 255),
+                1: (255, 0, 0, 255),
+                255: (255, 255, 0, 255),
+            },
+            "seq": [
+                ((1, 2), (255, 0, 0, 255)),
+                ((2, 3), (255, 240, 255, 255)),
+            ],
+        }
+    )
+
+    cmaps = ColorMapFactory(supported_colormaps=cmaps)
+
+    app = FastAPI()
+    app.include_router(cmaps.router)
+    client = TestClient(app)
+
+    response = client.get("/colorMaps")
+    assert response.status_code == 200
+    assert "cust" in response.json()["colorMaps"]
+    assert "negative" in response.json()["colorMaps"]
+    assert "seq" in response.json()["colorMaps"]
+    assert "viridis" in response.json()["colorMaps"]
+
+    response = client.get("/colorMaps/viridis")
+    assert response.status_code == 200
+
+    response = client.get("/colorMaps/cust")
+    assert response.status_code == 200
+
+    response = client.get("/colorMaps/negative")
+    assert response.status_code == 200
+
+    response = client.get("/colorMaps/seq")
+    assert response.status_code == 200
+
+    response = client.get("/colorMaps/yo")
+    assert response.status_code == 422
+
+    response = client.get("/colorMaps/viridis", params={"format": "png"})
+    assert response.status_code == 200
+    meta = parse_img(response.content)
+    assert meta["dtype"] == "uint8"
+    assert meta["count"] == 4
+    assert meta["width"] == 256
+    assert meta["height"] == 20
+
+    response = client.get(
+        "/colorMaps/viridis", params={"format": "png", "orientation": "vertical"}
+    )
+    assert response.status_code == 200
+    meta = parse_img(response.content)
+    assert meta["dtype"] == "uint8"
+    assert meta["count"] == 4
+    assert meta["width"] == 20
+    assert meta["height"] == 256
+
+    response = client.get(
+        "/colorMaps/viridis", params={"format": "png", "width": 1000, "height": 100}
+    )
+    assert response.status_code == 200
+    meta = parse_img(response.content)
+    assert meta["dtype"] == "uint8"
+    assert meta["count"] == 4
+    assert meta["width"] == 1000
+    assert meta["height"] == 100
+
+    response = client.get("/colorMaps/cust", params={"format": "png"})
+    assert response.status_code == 200
+    meta = parse_img(response.content)
+    assert meta["dtype"] == "uint8"
+    assert meta["count"] == 4
+    assert meta["width"] == 256
+    assert meta["height"] == 20
+
+    response = client.get(
+        "/colorMaps/cust", params={"format": "png", "orientation": "vertical"}
+    )
+    assert response.status_code == 200
+    meta = parse_img(response.content)
+    assert meta["dtype"] == "uint8"
+    assert meta["count"] == 4
+    assert meta["width"] == 20
+    assert meta["height"] == 256
+
+    response = client.get("/colorMaps/negative", params={"format": "png"})
+    assert response.status_code == 200
+    meta = parse_img(response.content)
+    assert meta["dtype"] == "uint8"
+    assert meta["count"] == 4
+    assert meta["width"] == 256
+    assert meta["height"] == 20
+
+    response = client.get(
+        "/colorMaps/negative", params={"format": "png", "orientation": "vertical"}
+    )
+    assert response.status_code == 200
+    meta = parse_img(response.content)
+    assert meta["dtype"] == "uint8"
+    assert meta["count"] == 4
+    assert meta["width"] == 20
+    assert meta["height"] == 256
+
+    response = client.get("/colorMaps/seq", params={"format": "png"})
+    assert response.status_code == 200
+    meta = parse_img(response.content)
+    assert meta["dtype"] == "uint8"
+    assert meta["count"] == 4
+    assert meta["width"] == 256
+    assert meta["height"] == 20
+
+    response = client.get(
+        "/colorMaps/seq", params={"format": "png", "orientation": "vertical"}
+    )
+    assert response.status_code == 200
+    meta = parse_img(response.content)
+    assert meta["dtype"] == "uint8"
+    assert meta["count"] == 4
+    assert meta["width"] == 20
+    assert meta["height"] == 256
diff --git a/src/titiler/core/titiler/core/factory.py b/src/titiler/core/titiler/core/factory.py
index 5fb38772a..bf3f5c5c6 100644
--- a/src/titiler/core/titiler/core/factory.py
+++ b/src/titiler/core/titiler/core/factory.py
@@ -2,10 +2,22 @@
 
 import abc
 from dataclasses import dataclass, field
-from typing import Any, Callable, Dict, List, Literal, Optional, Tuple, Type, Union
+from typing import (
+    Any,
+    Callable,
+    Dict,
+    List,
+    Literal,
+    Optional,
+    Sequence,
+    Tuple,
+    Type,
+    Union,
+)
 from urllib.parse import urlencode
 
 import jinja2
+import numpy
 import rasterio
 from fastapi import APIRouter, Body, Depends, Path, Query
 from fastapi.dependencies.utils import get_parameterless_sub_dependant
@@ -16,9 +28,11 @@
 from morecantile import tms as morecantile_tms
 from morecantile.defaults import TileMatrixSets
 from pydantic import conint
+from rio_tiler.colormap import ColorMaps
+from rio_tiler.colormap import cmap as default_cmap
 from rio_tiler.constants import WGS84_CRS
 from rio_tiler.io import BaseReader, MultiBandReader, MultiBaseReader, Reader
-from rio_tiler.models import Bounds, Info
+from rio_tiler.models import Bounds, ImageData, Info
 from rio_tiler.types import ColorMapType
 from starlette.requests import Request
 from starlette.responses import HTMLResponse, Response
@@ -56,6 +70,7 @@
 from titiler.core.models.mapbox import TileJSON
 from titiler.core.models.OGC import TileMatrixSetList
 from titiler.core.models.responses import (
+    ColorMapsList,
     InfoGeoJSON,
     MultiBaseInfo,
     MultiBaseInfoGeoJSON,
@@ -1731,3 +1746,176 @@ def algorithm_metadata(
         ):
             """Retrieve the metadata of the specified algorithm."""
             return metadata(self.supported_algorithm.get(algorithm))
+
+
+@dataclass
+class ColorMapFactory:
+    """Colormap endpoints Factory."""
+
+    # Supported colormaps
+    supported_colormaps: ColorMaps = default_cmap
+
+    # FastAPI router
+    router: APIRouter = field(default_factory=APIRouter)
+
+    def url_for(self, request: Request, name: str, **path_params: Any) -> str:
+        """Return full url (with prefix) for a specific endpoint."""
+        url_path = self.router.url_path_for(name, **path_params)
+        base_url = str(request.base_url)
+        return str(url_path.make_absolute_url(base_url=base_url))
+
+    def __post_init__(self):  # noqa: C901
+        """Post Init: register routes"""
+
+        @self.router.get(
+            "/colorMaps",
+            response_model=ColorMapsList,
+            response_model_exclude_none=True,
+            summary="Retrieve the list of available colormaps.",
+            operation_id="getColorMaps",
+        )
+        def available_colormaps(request: Request):
+            """Retrieve the list of available colormaps."""
+            return {
+                "colorMaps": self.supported_colormaps.list(),
+                "links": [
+                    {
+                        "title": "List of available colormaps",
+                        "href": self.url_for(
+                            request,
+                            "available_colormaps",
+                        ),
+                        "type": "application/json",
+                        "rel": "self",
+                    },
+                    {
+                        "title": "Retrieve colorMap metadata",
+                        "href": self.url_for(
+                            request, "colormap_metadata", colorMapId="{colorMapId}"
+                        ),
+                        "type": "application/json",
+                        "rel": "data",
+                        "templated": True,
+                    },
+                    {
+                        "title": "Retrieve colorMap as image",
+                        "href": self.url_for(
+                            request, "colormap_metadata", colorMapId="{colorMapId}"
+                        )
+                        + "?format=png",
+                        "type": "image/png",
+                        "rel": "data",
+                        "templated": True,
+                    },
+                ],
+            }
+
+        @self.router.get(
+            "/colorMaps/{colorMapId}",
+            response_model=ColorMapType,
+            summary="Retrieve the colorMap metadata or image.",
+            operation_id="getColorMap",
+            responses={
+                200: {
+                    "content": {
+                        "application/json": {},
+                        "image/png": {},
+                        "image/jpeg": {},
+                        "image/jpg": {},
+                        "image/webp": {},
+                        "image/jp2": {},
+                        "image/tiff; application=geotiff": {},
+                        "application/x-binary": {},
+                    }
+                },
+            },
+        )
+        def colormap_metadata(
+            colormap: Annotated[
+                Literal[tuple(self.supported_colormaps.list())],
+                Path(description="ColorMap name", alias="colorMapId"),
+            ],
+            # Image Output Options
+            format: Annotated[
+                Optional[ImageType],
+                Query(
+                    description="Return colorMap as Image.",
+                ),
+            ] = None,
+            orientation: Annotated[
+                Optional[Literal["vertical", "horizontal"]],
+                Query(
+                    description="Image Orientation.",
+                ),
+            ] = None,
+            height: Annotated[
+                Optional[int],
+                Query(
+                    description="Image Height (default to 20px for horizontal or 256px for vertical).",
+                ),
+            ] = None,
+            width: Annotated[
+                Optional[int],
+                Query(
+                    description="Image Width (default to 256px for horizontal or 20px for vertical).",
+                ),
+            ] = None,
+        ):
+            """Retrieve the metadata of the specified colormap."""
+            cmap = self.supported_colormaps.get(colormap)
+
+            if format:
+                ###############################################################
+                # SEQUENCE CMAP
+                if isinstance(cmap, Sequence):
+                    values = [minv for ((minv, _), _) in cmap]
+                    arr = numpy.array([values] * 20)
+
+                    if orientation == "vertical":
+                        height = height or 256 if len(values) < 256 else len(values)
+                    else:
+                        width = width or 256 if len(values) < 256 else len(values)
+
+                ###############################################################
+                # DISCRETE CMAP
+                elif len(cmap) != 256 or max(cmap) >= 256 or min(cmap) < 0:
+                    values = list(cmap)
+                    arr = numpy.array([values] * 20)
+
+                    if orientation == "vertical":
+                        height = height or 256 if len(values) < 256 else len(values)
+                    else:
+                        width = width or 256 if len(values) < 256 else len(values)
+
+                ###############################################################
+                # LINEAR CMAP
+                else:
+                    cmin, cmax = min(cmap), max(cmap)
+                    arr = numpy.array(
+                        [
+                            numpy.round(numpy.linspace(cmin, cmax, num=256)).astype(
+                                numpy.uint8
+                            )
+                        ]
+                        * 20
+                    )
+
+                if orientation == "vertical":
+                    arr = arr.transpose([1, 0])
+
+                img = ImageData(arr)
+
+                width = width or img.width
+                height = height or img.height
+                if width != img.width or height != img.height:
+                    img = img.resize(height, width)
+
+                return Response(
+                    img.render(img_format=format.driver, colormap=cmap),
+                    media_type=format.mediatype,
+                )
+
+            if isinstance(cmap, Sequence):
+                return [(k, numpy.array(v).tolist()) for (k, v) in cmap]
+            else:
+                return {k: numpy.array(v).tolist() for k, v in cmap.items()}
diff --git a/src/titiler/core/titiler/core/models/OGC.py b/src/titiler/core/titiler/core/models/OGC.py
index 91744406a..154cff33b 100644
--- a/src/titiler/core/titiler/core/models/OGC.py
+++ b/src/titiler/core/titiler/core/models/OGC.py
@@ -3,7 +3,10 @@
 
 from typing import List, Optional
 
-from pydantic import AnyHttpUrl, BaseModel
+from pydantic import AnyHttpUrl, BaseModel, Field
+from typing_extensions import Annotated
+
+from titiler.core.resources.enums import MediaType
 
 
 class TileMatrixSetLink(BaseModel):
@@ -38,3 +41,78 @@ class TileMatrixSetList(BaseModel):
     """
 
     tileMatrixSets: List[TileMatrixSetRef]
+
+
+class Link(BaseModel):
+    """Link model.
+
+    Ref: https://github.com/opengeospatial/ogcapi-tiles/blob/master/openapi/schemas/common-core/link.yaml
+
+    Code generated using https://github.com/koxudaxi/datamodel-code-generator/
+    """
+
+    href: Annotated[
+        str,
+        Field(
+            json_schema_extra={
+                "description": "Supplies the URI to a remote resource (or resource fragment).",
+                "examples": ["http://data.example.com/buildings/123"],
+            }
+        ),
+    ]
+    rel: Annotated[
+        str,
+        Field(
+            json_schema_extra={
+                "description": "The type or semantics of the relation.",
+                "examples": ["alternate"],
+            }
+        ),
+    ]
+    type: Annotated[
+        Optional[MediaType],
+        Field(
+            json_schema_extra={
+                "description": "A hint indicating what the media type of the result of dereferencing the link should be.",
+                "examples": ["application/geo+json"],
+            }
+        ),
+    ] = None
+    templated: Annotated[
+        Optional[bool],
+        Field(
+            json_schema_extra={
+                "description": "This flag set to true if the link is a URL template.",
+            }
+        ),
+    ] = None
+    varBase: Annotated[
+        Optional[str],
+        Field(
+            json_schema_extra={
+                "description": "A base path to retrieve semantic information about the variables used in URL template.",
+                "examples": ["/ogcapi/vars/"],
+            }
+        ),
+    ] = None
+    hreflang: Annotated[
+        Optional[str],
+        Field(
+            json_schema_extra={
+                "description": "A hint indicating what the language of the result of dereferencing the link should be.",
+                "examples": ["en"],
+            }
+        ),
+    ] = None
+    title: Annotated[
+        Optional[str],
+        Field(
+            json_schema_extra={
+                "description": "Used to label the destination of a link such that it can be used as a human-readable identifier.",
+                "examples": ["Trierer Strasse 70, 53115 Bonn"],
+            }
+        ),
+    ] = None
+    length: Optional[int] = None
+
+    model_config = {"use_enum_values": True}
diff --git a/src/titiler/core/titiler/core/models/responses.py b/src/titiler/core/titiler/core/models/responses.py
index 1314655fc..f79db332a 100644
--- a/src/titiler/core/titiler/core/models/responses.py
+++ b/src/titiler/core/titiler/core/models/responses.py
@@ -7,6 +7,8 @@
 from pydantic import BaseModel
 from rio_tiler.models import BandStatistics, Info
 
+from titiler.core.models.OGC import Link
+
 
 class Point(BaseModel):
     """
@@ -44,3 +46,10 @@ class StatisticsInGeoJSON(BaseModel):
 
 MultiBaseStatistics = Dict[str, Statistics]
 MultiBaseStatisticsGeoJSON = StatisticsGeoJSON
+
+
+class ColorMapsList(BaseModel):
+    """Model for colormap list."""
+
+    colorMaps: List[str]
+    links: List[Link]
diff --git a/src/titiler/core/titiler/core/resources/enums.py b/src/titiler/core/titiler/core/resources/enums.py
index 1f0fbfa32..42d23246c 100644
--- a/src/titiler/core/titiler/core/resources/enums.py
+++ b/src/titiler/core/titiler/core/resources/enums.py
@@ -23,7 +23,13 @@ class MediaType(str, Enum):
     html = "text/html"
     text = "text/plain"
     pbf = "application/x-protobuf"
-    mvt = "application/x-protobuf"
+    mvt = "application/vnd.mapbox-vector-tile"
+    ndjson = "application/ndjson"
+    geojsonseq = "application/geo+json-seq"
+    schemajson = "application/schema+json"
+    csv = "text/csv"
+    openapi30_json = "application/vnd.oai.openapi+json;version=3.0"
+    openapi30_yaml = "application/vnd.oai.openapi;version=3.0"
 
 
 class ImageDriver(str, Enum):