Skip to content

Commit 4aa57c3

Browse files
committed
update xarray example app
1 parent 84077b0 commit 4aa57c3

File tree

1 file changed

+207
-7
lines changed

1 file changed

+207
-7
lines changed

src/titiler/xarray/examples/main.py

Lines changed: 207 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,47 +7,85 @@
77
# ///
88
"""Example of Application."""
99

10-
from fastapi import FastAPI
10+
from typing import Annotated, Literal, Optional
11+
12+
import rasterio
13+
import xarray
14+
import zarr
15+
from fastapi import FastAPI, Query
1116
from starlette.middleware.cors import CORSMiddleware
17+
from starlette.requests import Request
1218
from starlette_cramjam.middleware import CompressionMiddleware
1319

1420
from titiler.core.errors import DEFAULT_STATUS_CODES, add_exception_handlers
1521
from titiler.core.factory import AlgorithmFactory, ColorMapFactory, TMSFactory
1622
from titiler.core.middleware import CacheControlMiddleware
23+
from titiler.core.models.OGC import Conformance, Landing
24+
from titiler.core.resources.enums import MediaType
25+
from titiler.core.templating import create_html_response
26+
from titiler.core.utils import accept_media_type, update_openapi
27+
from titiler.xarray import __version__ as titiler_version
1728
from titiler.xarray.extensions import DatasetMetadataExtension
1829
from titiler.xarray.factory import TilerFactory
1930

2031
app = FastAPI(
2132
title="TiTiler with support of Multidimensional dataset",
33+
description="""A modern dynamic tile server built on top of FastAPI and Rasterio/GDAL/Xarray for Zarr/NetCDF dataset.
34+
35+
---
36+
37+
**Documentation**: <a href="https://developmentseed.org/titiler/" target="_blank">https://developmentseed.org/titiler/</a>
38+
39+
**Source Code**: <a href="https://github.com/developmentseed/titiler" target="_blank">https://github.com/developmentseed/titiler</a>
40+
41+
---
42+
""",
2243
openapi_url="/api",
2344
docs_url="/api.html",
24-
version="0.1.0",
45+
version=titiler_version,
2546
)
2647

48+
update_openapi(app)
49+
50+
TITILER_CONFORMS_TO = {
51+
"http://www.opengis.net/spec/ogcapi-common-1/1.0/req/core",
52+
"http://www.opengis.net/spec/ogcapi-common-1/1.0/req/landing-page",
53+
"http://www.opengis.net/spec/ogcapi-common-1/1.0/req/oas30",
54+
"http://www.opengis.net/spec/ogcapi-common-1/1.0/req/html",
55+
"http://www.opengis.net/spec/ogcapi-common-1/1.0/req/json",
56+
}
57+
2758

2859
md = TilerFactory(
29-
router_prefix="/md",
3060
extensions=[
3161
DatasetMetadataExtension(),
3262
],
3363
)
34-
app.include_router(md.router, prefix="/md", tags=["Multi Dimensional"])
64+
app.include_router(md.router, tags=["Multi Dimensional"])
65+
66+
TITILER_CONFORMS_TO.update(md.conforms_to)
3567

3668
# TileMatrixSets endpoints
37-
app.include_router(TMSFactory().router, tags=["Tiling Schemes"])
69+
tms = TMSFactory()
70+
app.include_router(tms.router, tags=["Tiling Schemes"])
71+
TITILER_CONFORMS_TO.update(tms.conforms_to)
3872

3973
###############################################################################
4074
# Algorithms endpoints
75+
algorithms = AlgorithmFactory()
4176
app.include_router(
42-
AlgorithmFactory().router,
77+
algorithms.router,
4378
tags=["Algorithms"],
4479
)
80+
TITILER_CONFORMS_TO.update(algorithms.conforms_to)
4581

4682
# Colormaps endpoints
83+
cmaps = ColorMapFactory()
4784
app.include_router(
48-
ColorMapFactory().router,
85+
cmaps.router,
4986
tags=["ColorMaps"],
5087
)
88+
TITILER_CONFORMS_TO.update(cmaps.conforms_to)
5189

5290
add_exception_handlers(app, DEFAULT_STATUS_CODES)
5391

@@ -80,6 +118,168 @@
80118
)
81119

82120

121+
@app.get(
122+
"/healthz",
123+
description="Health Check.",
124+
summary="Health Check.",
125+
operation_id="healthCheck",
126+
tags=["Health Check"],
127+
)
128+
def application_health_check():
129+
"""Health check."""
130+
return {
131+
"versions": {
132+
"titiler": titiler_version,
133+
"rasterio": rasterio.__version__,
134+
"gdal": rasterio.__gdal_version__,
135+
"proj": rasterio.__proj_version__,
136+
"geos": rasterio.__geos_version__,
137+
"xarray": xarray.__version__,
138+
"zarr": zarr.__version__,
139+
}
140+
}
141+
142+
143+
@app.get(
144+
"/",
145+
response_model=Landing,
146+
response_model_exclude_none=True,
147+
responses={
148+
200: {
149+
"content": {
150+
"text/html": {},
151+
"application/json": {},
152+
}
153+
},
154+
},
155+
tags=["OGC Common"],
156+
)
157+
def landing(
158+
request: Request,
159+
f: Annotated[
160+
Optional[Literal["html", "json"]],
161+
Query(
162+
description="Response MediaType. Defaults to endpoint's default or value defined in `accept` header."
163+
),
164+
] = None,
165+
):
166+
"""TiTiler landing page."""
167+
data = {
168+
"title": "TiTiler + Xarray",
169+
"description": "A modern dynamic tile server built on top of FastAPI and Rasterio/GDAL/Xarray for Zarr/NetCDF dataset.",
170+
"links": [
171+
{
172+
"title": "Landing page",
173+
"href": str(request.url_for("landing")),
174+
"type": "text/html",
175+
"rel": "self",
176+
},
177+
{
178+
"title": "The API definition (JSON)",
179+
"href": str(request.url_for("openapi")),
180+
"type": "application/vnd.oai.openapi+json;version=3.0",
181+
"rel": "service-desc",
182+
},
183+
{
184+
"title": "The API documentation",
185+
"href": str(request.url_for("swagger_ui_html")),
186+
"type": "text/html",
187+
"rel": "service-doc",
188+
},
189+
{
190+
"title": "Conformance Declaration",
191+
"href": str(request.url_for("conformance")),
192+
"type": "text/html",
193+
"rel": "http://www.opengis.net/def/rel/ogc/1.0/conformance",
194+
},
195+
{
196+
"title": "TiTiler Documentation (external link)",
197+
"href": "https://developmentseed.org/titiler/",
198+
"type": "text/html",
199+
"rel": "doc",
200+
},
201+
{
202+
"title": "TiTiler.Xarray source code (external link)",
203+
"href": "https://github.com/developmentseed/titiler/tree/main/src/titiler/xarray",
204+
"type": "text/html",
205+
"rel": "doc",
206+
},
207+
],
208+
}
209+
210+
output_type: Optional[MediaType]
211+
if f:
212+
output_type = MediaType[f]
213+
else:
214+
accepted_media = [MediaType.html, MediaType.json]
215+
output_type = accept_media_type(
216+
request.headers.get("accept", ""), accepted_media
217+
)
218+
219+
if output_type == MediaType.html:
220+
return create_html_response(
221+
request,
222+
data,
223+
title="TiTiler",
224+
template_name="landing",
225+
)
226+
227+
return data
228+
229+
230+
@app.get(
231+
"/conformance",
232+
response_model=Conformance,
233+
response_model_exclude_none=True,
234+
responses={
235+
200: {
236+
"content": {
237+
"text/html": {},
238+
"application/json": {},
239+
}
240+
},
241+
},
242+
tags=["OGC Common"],
243+
)
244+
def conformance(
245+
request: Request,
246+
f: Annotated[
247+
Optional[Literal["html", "json"]],
248+
Query(
249+
description="Response MediaType. Defaults to endpoint's default or value defined in `accept` header."
250+
),
251+
] = None,
252+
):
253+
"""Conformance classes.
254+
255+
Called with `GET /conformance`.
256+
257+
Returns:
258+
Conformance classes which the server conforms to.
259+
260+
"""
261+
data = {"conformsTo": sorted(TITILER_CONFORMS_TO)}
262+
263+
output_type: Optional[MediaType]
264+
if f:
265+
output_type = MediaType[f]
266+
else:
267+
accepted_media = [MediaType.html, MediaType.json]
268+
output_type = accept_media_type(
269+
request.headers.get("accept", ""), accepted_media
270+
)
271+
272+
if output_type == MediaType.html:
273+
return create_html_response(
274+
request,
275+
data,
276+
title="Conformance",
277+
template_name="conformance",
278+
)
279+
280+
return data
281+
282+
83283
if __name__ == "__main__":
84284
import uvicorn
85285

0 commit comments

Comments
 (0)