]> git.openstreetmap.org Git - nominatim.git/commitdiff
add support for starlette framework
authorSarah Hoffmann <lonvia@denofr.de>
Mon, 5 Dec 2022 10:32:57 +0000 (11:32 +0100)
committerSarah Hoffmann <lonvia@denofr.de>
Tue, 3 Jan 2023 09:03:00 +0000 (10:03 +0100)
nominatim/cli.py
nominatim/server/starlette/__init__.py [new file with mode: 0644]
nominatim/server/starlette/server.py [new file with mode: 0644]

index 34abb617efe3346aa156b3055ab36da045b7b594..7143b7d676c6d9aafa8c5f5aa9f7cbf71813d08c 100644 (file)
@@ -202,7 +202,7 @@ class AdminServe:
     for testing and development. Do not use it in production setups!
 
     There are different webservers available. The default 'php' engine
-    runs the classic PHP frontend. 'sanic' and 'falcon' are Python servers
+    runs the classic PHP frontend. The other engines are Python servers
     which run the new Python frontend code. This is highly experimental
     at the moment and may not include the full API.
 
@@ -214,7 +214,7 @@ class AdminServe:
         group.add_argument('--server', default='127.0.0.1:8088',
                            help='The address the server will listen to.')
         group.add_argument('--engine', default='php',
-                           choices=('php', 'sanic', 'falcon'),
+                           choices=('php', 'sanic', 'falcon', 'starlette'),
                            help='Webserver framework to run. (default: php)')
 
 
@@ -236,11 +236,15 @@ class AdminServe:
 
                 app = nominatim.server.sanic.server.get_application(args.project_dir)
                 app.run(host=host, port=port, debug=True)
-            elif args.engine == 'falcon':
+            else:
                 import uvicorn
-                import nominatim.server.falcon.server
 
-                app = nominatim.server.falcon.server.get_application(args.project_dir)
+                if args.engine == 'falcon':
+                    import nominatim.server.falcon.server as server_module
+                elif args.engine == 'starlette':
+                    import nominatim.server.starlette.server as server_module
+
+                app = server_module.get_application(args.project_dir)
                 uvicorn.run(app, host=host, port=port)
 
         return 0
diff --git a/nominatim/server/starlette/__init__.py b/nominatim/server/starlette/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/nominatim/server/starlette/server.py b/nominatim/server/starlette/server.py
new file mode 100644 (file)
index 0000000..bfc552f
--- /dev/null
@@ -0,0 +1,64 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# This file is part of Nominatim. (https://nominatim.org)
+#
+# Copyright (C) 2022 by the Nominatim developer community.
+# For a full list of authors see the git log.
+"""
+Server implementation using the starlette webserver framework.
+"""
+from pathlib import Path
+
+from starlette.applications import Starlette
+from starlette.routing import Route
+from starlette.exceptions import HTTPException
+from starlette.responses import Response
+
+from nominatim.api import NominatimAPIAsync
+from nominatim.apicmd.status import StatusResult
+import nominatim.result_formatter.v1 as formatting
+
+CONTENT_TYPE = {
+  'text': 'text/plain; charset=utf-8',
+  'xml': 'text/xml; charset=utf-8'
+}
+
+FORMATTERS = {
+    StatusResult: formatting.create(StatusResult)
+}
+
+
+def parse_format(request, rtype, default):
+    fmt = request.query_params.get('format', default=default)
+    fmtter = FORMATTERS[rtype]
+
+    if not fmtter.supports_format(fmt):
+        raise HTTPException(400, detail="Parameter 'format' must be one of: " +
+                                        ', '.join(fmtter.list_formats()))
+
+    request.state.format = fmt
+    request.state.formatter = fmtter
+
+
+def format_response(request, result):
+    fmt = request.state.format
+    return Response(request.state.formatter.format(result, fmt),
+                    media_type=CONTENT_TYPE.get(fmt, 'application/json'))
+
+
+async def on_status(request):
+    parse_format(request, StatusResult, 'text')
+    result = await request.app.state.API.status()
+    return format_response(request, result)
+
+
+V1_ROUTES = [
+    Route('/status', endpoint=on_status)
+]
+
+def get_application(project_dir: Path) -> Starlette:
+    app = Starlette(debug=True, routes=V1_ROUTES)
+
+    app.state.API = NominatimAPIAsync(project_dir)
+
+    return app