Skip to content

Commit f5673d9

Browse files
committed
add HTML output for stac-api
1 parent 28e70fa commit f5673d9

File tree

14 files changed

+1342
-10
lines changed

14 files changed

+1342
-10
lines changed

runtimes/eoapi/stac/eoapi/stac/app.py

Lines changed: 121 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,21 @@
33
import logging
44
from contextlib import asynccontextmanager
55

6+
import attr
67
import jinja2
78
from eoapi.auth_utils import OpenIdConnectAuth, OpenIdConnectSettings
89
from fastapi import FastAPI
910
from fastapi.responses import ORJSONResponse
1011
from stac_fastapi.api.app import StacApi
1112
from stac_fastapi.api.models import (
13+
CollectionUri,
14+
EmptyRequest,
1215
ItemCollectionUri,
13-
create_get_request_model,
16+
ItemUri,
1417
create_post_request_model,
1518
create_request_model,
1619
)
20+
from stac_fastapi.api.routes import create_async_endpoint
1721
from stac_fastapi.extensions.core import (
1822
FieldsExtension,
1923
FilterExtension,
@@ -23,21 +27,24 @@
2327
)
2428
from stac_fastapi.extensions.third_party import BulkTransactionExtension
2529
from stac_fastapi.pgstac.config import Settings
26-
from stac_fastapi.pgstac.core import CoreCrudClient
2730
from stac_fastapi.pgstac.db import close_db_connection, connect_to_db
2831
from stac_fastapi.pgstac.extensions import QueryExtension
2932
from stac_fastapi.pgstac.extensions.filter import FiltersClient
3033
from stac_fastapi.pgstac.transactions import BulkTransactionsClient, TransactionsClient
3134
from stac_fastapi.pgstac.types.search import PgstacSearch
35+
from stac_fastapi.types.search import BaseSearchGetRequest
36+
from stac_pydantic import api
37+
from stac_pydantic.shared import MimeTypes
3238
from starlette.middleware import Middleware
3339
from starlette.middleware.cors import CORSMiddleware
3440
from starlette.requests import Request
3541
from starlette.responses import HTMLResponse
3642
from starlette.templating import Jinja2Templates
3743
from starlette_cramjam.middleware import CompressionMiddleware
3844

45+
from .client import PgSTACClient
3946
from .config import ApiSettings
40-
from .extension import TiTilerExtension
47+
from .extension import HTMLorGeoJSONGetRequest, HTMLorJSONGetRequest, TiTilerExtension
4148
from .logs import init_logging
4249

4350
jinja2_env = jinja2.Environment(
@@ -115,19 +122,121 @@ async def lifespan(app: FastAPI):
115122
)
116123

117124
# Custom Models
118-
items_get_model = ItemCollectionUri
119125
if any(isinstance(ext, TokenPaginationExtension) for ext in extensions):
120126
items_get_model = create_request_model(
121127
model_name="ItemCollectionUri",
122128
base_model=ItemCollectionUri,
123-
mixins=[TokenPaginationExtension().GET],
129+
mixins=[TokenPaginationExtension().GET, HTMLorGeoJSONGetRequest],
130+
request_type="GET",
131+
)
132+
else:
133+
items_get_model = create_request_model(
134+
model_name="ItemCollectionUri",
135+
base_model=ItemCollectionUri,
136+
mixins=[HTMLorGeoJSONGetRequest],
124137
request_type="GET",
125138
)
126139

127-
search_get_model = create_get_request_model(extensions)
140+
search_get_model = create_request_model(
141+
"SearchGetRequest",
142+
base_model=BaseSearchGetRequest,
143+
extensions=extensions,
144+
mixins=[HTMLorGeoJSONGetRequest],
145+
request_type="GET",
146+
)
128147
search_post_model = create_post_request_model(extensions, base_model=PgstacSearch)
148+
collections_get_model = create_request_model(
149+
model_name="CollectionsModel",
150+
base_model=EmptyRequest,
151+
mixins=[HTMLorJSONGetRequest],
152+
request_type="GET",
153+
)
154+
collection_get_model = create_request_model(
155+
model_name="CollectionUri",
156+
base_model=CollectionUri,
157+
mixins=[HTMLorJSONGetRequest],
158+
request_type="GET",
159+
)
160+
item_get_model = create_request_model(
161+
model_name="ItemUri",
162+
base_model=ItemUri,
163+
mixins=[HTMLorGeoJSONGetRequest],
164+
request_type="GET",
165+
)
166+
conformance_get_model = create_request_model(
167+
model_name="ConformanceModel",
168+
base_model=EmptyRequest,
169+
mixins=[HTMLorJSONGetRequest],
170+
request_type="GET",
171+
)
172+
landing_get_model = create_request_model(
173+
model_name="LandingModel",
174+
base_model=EmptyRequest,
175+
mixins=[HTMLorJSONGetRequest],
176+
request_type="GET",
177+
)
178+
179+
180+
@attr.s
181+
class CustomStacApi(StacApi):
182+
def register_landing_page(self):
183+
"""Register landing page (GET /).
184+
185+
Returns:
186+
None
187+
"""
188+
self.router.add_api_route(
189+
name="Landing Page",
190+
path="/",
191+
response_model=(
192+
api.LandingPage if self.settings.enable_response_models else None
193+
),
194+
responses={
195+
200: {
196+
"content": {
197+
MimeTypes.json.value: {},
198+
},
199+
"model": api.LandingPage,
200+
},
201+
},
202+
response_class=self.response_class,
203+
response_model_exclude_unset=False,
204+
response_model_exclude_none=True,
205+
methods=["GET"],
206+
endpoint=create_async_endpoint(self.client.landing_page, landing_get_model),
207+
)
208+
209+
def register_conformance_classes(self):
210+
"""Register conformance classes (GET /conformance).
211+
212+
Returns:
213+
None
214+
"""
215+
self.router.add_api_route(
216+
name="Conformance Classes",
217+
path="/conformance",
218+
response_model=(
219+
api.Conformance if self.settings.enable_response_models else None
220+
),
221+
responses={
222+
200: {
223+
"content": {
224+
MimeTypes.json.value: {},
225+
},
226+
"model": api.Conformance,
227+
},
228+
},
229+
response_class=self.response_class,
230+
response_model_exclude_unset=True,
231+
response_model_exclude_none=True,
232+
methods=["GET"],
233+
endpoint=create_async_endpoint(
234+
self.client.conformance, conformance_get_model
235+
),
236+
)
237+
129238

130-
api = StacApi(
239+
stac_api = CustomStacApi( # type: ignore
131240
app=FastAPI(
132241
title=api_settings.name,
133242
lifespan=lifespan,
@@ -143,14 +252,17 @@ async def lifespan(app: FastAPI):
143252
description=api_settings.name,
144253
settings=settings,
145254
extensions=extensions,
146-
client=CoreCrudClient(post_request_model=search_post_model),
255+
client=PgSTACClient(post_request_model=search_post_model), # type: ignore
147256
items_get_request_model=items_get_model,
257+
item_get_request_model=item_get_model,
258+
collections_get_request_model=collections_get_model,
259+
collection_get_request_model=collection_get_model,
148260
search_get_request_model=search_get_model,
149261
search_post_request_model=search_post_model,
150262
response_class=ORJSONResponse,
151263
middlewares=middlewares,
152264
)
153-
app = api.app
265+
app = stac_api.app
154266

155267

156268
@app.get("/index.html", response_class=HTMLResponse)

0 commit comments

Comments
 (0)