浏览代码

Merge pull request #22 from zauberzeug/feature/parameter-injection

implement parameter injection for get decorator
Rodja Trappe 3 年之前
父节点
当前提交
dc7e4e4462
共有 2 个文件被更改,包括 32 次插入9 次删除
  1. 9 6
      main.py
  2. 23 3
      nicegui/routes.py

+ 9 - 6
main.py

@@ -484,17 +484,20 @@ 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/).
+If type-annotated, they are automatically converted to `bool`, `int`, `float` and `complex` values.
+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={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

+ 23 - 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,25 @@ 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()}
+            parameters = inspect.signature(func).parameters
+            for key in parameters:
+                if parameters[key].annotation.__name__ == 'bool':
+                    args[key] = bool(args[key])
+                if parameters[key].annotation.__name__ == 'int':
+                    args[key] = int(args[key])
+                elif parameters[key].annotation.__name__ == 'float':
+                    args[key] = float(args[key])
+                elif parameters[key].annotation.__name__ == 'complex':
+                    args[key] = complex(args[key])
+            if 'request' in parameters and 'request' not in args:
+                args['request'] = request
+            return func(**args)
+        self.add_route(routing.Route(path, decorated))
+        return decorated
     return decorator