瀏覽代碼

implement parameter injection for get decorator

Falko Schindler 3 年之前
父節點
當前提交
a70134cd73
共有 2 個文件被更改,包括 21 次插入9 次删除
  1. 8 6
      main.py
  2. 13 3
      nicegui/routes.py

+ 8 - 6
main.py

@@ -484,17 +484,19 @@ with example(add_route):
 get_decorator = """### Get decorator
 
 Syntactic sugar to add routes.
-Decorating a function with the `@ui.get` makes it available at the specified endpoint, e.g. `'/another/route/1'`.
+Decorating a function with the `@ui.get` makes it available at the specified endpoint, e.g. `'/another/route/<id>'`.
+
+Path parameters can be passed to the request handler like with [FastAPI](https://fastapi.tiangolo.com/tutorial/path-params/).
+An optional `request` argument gives access to the complete request object.
 """
 with example(get_decorator):
-    import starlette
+    from starlette import requests, responses
 
     @ui.get('/another/route/{id}')
-    def produce_plain_response(request):
-        path_param_id = request.path_params['id']
-        return starlette.responses.PlainTextResponse(f'Response {path_param_id}')
+    def produce_plain_response(id: str, request: requests.Request):
+        return responses.PlainTextResponse(f'{request.client.host} asked for {id=}')
 
-    ui.link('Try yet another route!', '/another/route/1')
+    ui.link('Try yet another route!', '/another/route/42')
 
 with example(ui.keyboard):
     from nicegui.events import KeyEventArguments

+ 13 - 3
nicegui/routes.py

@@ -1,4 +1,6 @@
-from starlette.routing import Route
+from functools import wraps
+import inspect
+from starlette import routing, requests
 from . import globals
 
 def add_route(self, route):
@@ -14,7 +16,15 @@ def get(self, path: str):
     :param path: string that starts with a '/'
     :return:
     """
+    *_, converters = routing.compile_path(path)
+
     def decorator(func):
-        self.add_route(Route(path, func))
-        return func
+        @wraps(func)
+        def decorated(request: requests.Request):
+            args = {name: converter.convert(request.path_params.get(name)) for name, converter in converters.items()}
+            if 'request' in inspect.signature(func).parameters:
+                args['request'] = request
+            return func(**args)
+        self.add_route(routing.Route(path, decorated))
+        return decorated
     return decorator