"""
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
import datetime as dt
import asyncio
}
@contextlib.asynccontextmanager
- async def lifespan(app: Starlette) -> None:
+ async def lifespan(app: Starlette) -> AsyncIterator[Any]:
app.state.API = NominatimAPIAsync(project_dir, environ)
config = app.state.API.config
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)
app.routes.append(Route(f"/{name}", endpoint=endpoint))
if legacy_urls:
Generic part of the server implementation of the v1 API.
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
import dataclasses
from urllib.parse import urlencode
from ..localization import Locales
from . import helpers
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,
return build_response(params, params.formatting().format_result(results, fmt, {}))
-ROUTES = [
- ('status', status_endpoint),
- ('details', details_endpoint),
- ('reverse', reverse_endpoint),
- ('lookup', lookup_endpoint),
- ('search', search_endpoint),
- ('deletable', deletable_endpoint),
- ('polygons', polygons_endpoint),
-]
+async def get_routes(api: NominatimAPIAsync) -> Sequence[Tuple[str, EndpointFunc]]:
+ routes = [
+ ('status', status_endpoint),
+ ('details', details_endpoint),
+ ('reverse', reverse_endpoint),
+ ('lookup', lookup_endpoint),
+ ('deletable', deletable_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