enable search endpoint only when search table is available

This commit is contained in:
Sarah Hoffmann 2024-11-13 22:53:33 +01:00
parent 754ff15ebd
commit 20d0fb35ce
4 changed files with 31 additions and 16 deletions

View File

@ -172,7 +172,7 @@ class APIMiddleware:
assert self.app is not None assert self.app is not None
legacy_urls = self.api.config.get_bool('SERVE_LEGACY_URLS') legacy_urls = self.api.config.get_bool('SERVE_LEGACY_URLS')
formatter = load_format_dispatcher('v1', self.api.config.project_dir) formatter = load_format_dispatcher('v1', self.api.config.project_dir)
for name, func in api_impl.ROUTES: for name, func in await api_impl.get_routes(self.api):
endpoint = EndpointWrapper(name, func, self.api, formatter) endpoint = EndpointWrapper(name, func, self.api, formatter)
self.app.add_route(f"/{name}", endpoint) self.app.add_route(f"/{name}", endpoint)
if legacy_urls: if legacy_urls:

View File

@ -7,7 +7,8 @@
""" """
Server implementation using the starlette webserver framework. Server implementation using the starlette webserver framework.
""" """
from typing import Any, Optional, Mapping, Callable, cast, Coroutine, Dict, Awaitable from typing import Any, Optional, Mapping, Callable, cast, Coroutine, Dict, \
Awaitable, AsyncIterator
from pathlib import Path from pathlib import Path
import datetime as dt import datetime as dt
import asyncio import asyncio
@ -150,12 +151,12 @@ def get_application(project_dir: Path,
} }
@contextlib.asynccontextmanager @contextlib.asynccontextmanager
async def lifespan(app: Starlette) -> None: async def lifespan(app: Starlette) -> AsyncIterator[Any]:
app.state.API = NominatimAPIAsync(project_dir, environ) app.state.API = NominatimAPIAsync(project_dir, environ)
config = app.state.API.config config = app.state.API.config
legacy_urls = config.get_bool('SERVE_LEGACY_URLS') legacy_urls = config.get_bool('SERVE_LEGACY_URLS')
for name, func in api_impl.ROUTES: for name, func in await api_impl.get_routes(app.state.API):
endpoint = _wrap_endpoint(func) endpoint = _wrap_endpoint(func)
app.routes.append(Route(f"/{name}", endpoint=endpoint)) app.routes.append(Route(f"/{name}", endpoint=endpoint))
if legacy_urls: if legacy_urls:

View File

@ -8,4 +8,4 @@
Implementation of API version v1 (aka the legacy version). Implementation of API version v1 (aka the legacy version).
""" """
from .server_glue import ROUTES as ROUTES from .server_glue import get_routes as get_routes

View File

@ -8,7 +8,7 @@
Generic part of the server implementation of the v1 API. Generic part of the server implementation of the v1 API.
Combine with the scaffolding provided for the various Python ASGI frameworks. Combine with the scaffolding provided for the various Python ASGI frameworks.
""" """
from typing import Optional, Any, Type, Dict, cast from typing import Optional, Any, Type, Dict, cast, Sequence, Tuple
from functools import reduce from functools import reduce
import dataclasses import dataclasses
from urllib.parse import urlencode from urllib.parse import urlencode
@ -25,7 +25,8 @@ from ..results import DetailedResult, ReverseResults, SearchResult, SearchResult
from ..localization import Locales from ..localization import Locales
from . import helpers from . import helpers
from ..server import content_types as ct from ..server import content_types as ct
from ..server.asgi_adaptor import ASGIAdaptor from ..server.asgi_adaptor import ASGIAdaptor, EndpointFunc
from ..sql.async_core_library import PGCORE_ERROR
def build_response(adaptor: ASGIAdaptor, output: str, status: int = 200, def build_response(adaptor: ASGIAdaptor, output: str, status: int = 200,
@ -417,12 +418,25 @@ async def polygons_endpoint(api: NominatimAPIAsync, params: ASGIAdaptor) -> Any:
return build_response(params, params.formatting().format_result(results, fmt, {})) return build_response(params, params.formatting().format_result(results, fmt, {}))
ROUTES = [ async def get_routes(api: NominatimAPIAsync) -> Sequence[Tuple[str, EndpointFunc]]:
('status', status_endpoint), routes = [
('details', details_endpoint), ('status', status_endpoint),
('reverse', reverse_endpoint), ('details', details_endpoint),
('lookup', lookup_endpoint), ('reverse', reverse_endpoint),
('search', search_endpoint), ('lookup', lookup_endpoint),
('deletable', deletable_endpoint), ('deletable', deletable_endpoint),
('polygons', polygons_endpoint), ('polygons', polygons_endpoint),
] ]
def has_search_name(conn: sa.engine.Connection) -> bool:
insp = sa.inspect(conn)
return insp.has_table('search_name')
try:
async with api.begin() as conn:
if await conn.connection.run_sync(has_search_name):
routes.append(('search', search_endpoint))
except (PGCORE_ERROR, sa.exc.OperationalError):
pass # ignored
return routes