@@ -20,7 +20,7 @@ class TornadoDynamicHandler(RequestHandler):
2020 """
2121
2222 def initialize (self , ** kwargs ):
23- self .endpoint = kwargs .get ("endpoint" )
23+ self .endpoints = kwargs .get ("endpoints" , {} )
2424 self .router = kwargs .get ("router" )
2525
2626 async def prepare (self ):
@@ -31,18 +31,23 @@ async def prepare(self):
3131 self .json_body = {}
3232 else :
3333 self .json_body = {}
34+ self .endpoint = self .endpoints .get (self .request .method .upper ())
3435
3536 async def handle_http_exception (self , e ):
3637 self .set_status (e .status_code )
3738 await self .finish (json_encode ({"detail" : str (e .log_message )}))
3839
3940 async def handle_request (self ):
41+ if not hasattr (self , "endpoint" ) or not self .endpoint :
42+ self .send_error (405 )
43+ return
44+
4045 query_params = {
4146 k : self .get_query_argument (k ) for k in self .request .query_arguments
4247 }
4348
4449 all_params = {** self .path_kwargs , ** query_params }
45- body = self . json_body
50+ body = getattr ( self , " json_body" , {})
4651 try :
4752 resolved_kwargs = self .router .resolve_endpoint_params (
4853 self .endpoint , all_params , body
@@ -60,15 +65,18 @@ async def handle_request(self):
6065 if isinstance (e , HTTPError ):
6166 await self .handle_http_exception (e )
6267 return
63- self .set_status (422 )
68+ self .set_status (500 )
6469 await self .finish (json_encode ({"detail" : str (e )}))
6570 return
6671 meta = getattr (self .endpoint , "__route_meta__" , {})
6772 status_code = meta .get ("status_code" , 200 )
6873 result = self .router ._serialize_response (result )
6974 self .set_status (status_code )
7075 self .set_header ("Content-Type" , "application/json" )
71- await self .finish (json_encode (result ))
76+ if status_code == 204 :
77+ await self .finish ()
78+ else :
79+ await self .finish (json_encode (result ))
7280
7381 async def get (self , * args , ** kwargs ):
7482 await self .handle_request ()
@@ -89,6 +97,8 @@ async def delete(self, *args, **kwargs):
8997class TornadoRouter (BaseRouter ):
9098 def __init__ (self , app : Application = None , ** kwargs ):
9199 self .routes = []
100+ self ._endpoint_map : dict [str , dict [str , Callable ]] = {}
101+ self ._registered_paths : set [str ] = set ()
92102 super ().__init__ (app , ** kwargs )
93103 if self .app is not None and (self .add_docs_route or self .add_openapi_route ):
94104 self ._register_docs_endpoints ()
@@ -98,57 +108,57 @@ def add_route(self, path: str, method: str, endpoint: Callable):
98108
99109 tornado_path = re .sub (r"{(\w+)}" , r"(?P<\1>[^/]+)" , path )
100110
101- spec = url (
102- tornado_path ,
103- TornadoDynamicHandler ,
104- name = endpoint .__name__ ,
105- kwargs = {"endpoint" : endpoint , "router" : self },
106- )
107- self .routes .append (spec )
108- if self .app is not None :
109- self .app .add_handlers (r".*" , [spec ])
111+ if tornado_path not in self ._endpoint_map :
112+ self ._endpoint_map [tornado_path ] = {}
113+ self ._endpoint_map [tornado_path ][method .upper ()] = endpoint
114+
115+ if tornado_path not in self ._registered_paths :
116+ self ._registered_paths .add (tornado_path )
117+ spec = url (
118+ tornado_path ,
119+ TornadoDynamicHandler ,
120+ name = f"route_{ len (self ._registered_paths )} " ,
121+ kwargs = {"endpoints" : self ._endpoint_map [tornado_path ], "router" : self },
122+ )
123+ self .routes .append (spec )
124+ if self .app is not None :
125+ self .app .add_handlers (r".*" , [spec ])
126+ else :
127+ for rule in self .routes :
128+ if rule .matcher .regex .pattern == f"{ tornado_path } $" :
129+ rule .target_kwargs ["endpoints" ] = self ._endpoint_map [tornado_path ]
130+ break
110131
111132 def _register_docs_endpoints (self ):
112133 router = self
113134
114- class OpenAPIHandler (TornadoDynamicHandler ):
135+ class OpenAPIHandler (RequestHandler ):
115136 async def get (self ):
116137 self .set_header ("Content-Type" , "application/json" )
117- self .write (self . router .openapi )
138+ self .write (json_encode ( router .openapi ) )
118139 await self .finish ()
119140
120- class SwaggerUIHandler (TornadoDynamicHandler ):
141+ class SwaggerUIHandler (RequestHandler ):
121142 async def get (self ):
122- html = self . router .render_swagger_ui (self . router .openapi_url )
143+ html = router .render_swagger_ui (router .openapi_url )
123144 self .set_header ("Content-Type" , "text/html" )
124145 self .write (html )
125146 await self .finish ()
126147
127- class RedocUIHandler (TornadoDynamicHandler ):
148+ class RedocUIHandler (RequestHandler ):
128149 async def get (self ):
129- html = self . router .render_redoc_ui (self . router .openapi_url )
150+ html = router .render_redoc_ui (router .openapi_url )
130151 self .set_header ("Content-Type" , "text/html" )
131152 self .write (html )
132153 await self .finish ()
133154
134155 spec_openapi = url (
135- self .openapi_url ,
136- OpenAPIHandler ,
137- name = "openapi-schema" ,
138- kwargs = {"router" : router },
156+ self .openapi_url , OpenAPIHandler , name = "openapi-schema" , kwargs = {}
139157 )
140158 spec_swagger = url (
141- self .docs_url ,
142- SwaggerUIHandler ,
143- name = "swagger-ui" ,
144- kwargs = {"router" : router },
145- )
146- spec_redoc = url (
147- self .redoc_url ,
148- RedocUIHandler ,
149- name = "redoc-ui" ,
150- kwargs = {"router" : router },
159+ self .docs_url , SwaggerUIHandler , name = "swagger-ui" , kwargs = {}
151160 )
161+ spec_redoc = url (self .redoc_url , RedocUIHandler , name = "redoc-ui" , kwargs = {})
152162 self .routes .extend ([spec_openapi , spec_swagger , spec_redoc ])
153163 if self .app is not None :
154164 self .app .add_handlers (r".*" , [spec_openapi , spec_swagger , spec_redoc ])
0 commit comments