50
50
# API GW/ALB decode non-safe URI chars; we must support them too
51
51
_UNSAFE_URI = r"%<> \[\]{}|^"
52
52
_NAMED_GROUP_BOUNDARY_PATTERN = rf"(?P\1[{ _SAFE_URI } { _UNSAFE_URI } \\w]+)"
53
+ _DEFAULT_OPENAPI_RESPONSE_DESCRIPTION = "Successful Response"
53
54
_ROUTE_REGEX = "^{}$"
54
55
55
56
if TYPE_CHECKING :
@@ -201,9 +202,13 @@ def __init__(
201
202
cors : bool ,
202
203
compress : bool ,
203
204
cache_control : Optional [str ],
204
- middlewares : Optional [List [ Callable [..., Response ]] ],
205
+ summary : Optional [str ],
205
206
description : Optional [str ],
207
+ responses : Optional [Dict [Union [int , str ], Dict [str , Any ]]],
208
+ response_description : Optional [str ],
206
209
tags : Optional [List ["Tag" ]],
210
+ operation_id : Optional [str ],
211
+ middlewares : Optional [List [Callable [..., Response ]]],
207
212
):
208
213
"""
209
214
@@ -212,10 +217,10 @@ def __init__(
212
217
213
218
method: str
214
219
The HTTP method, example "GET"
215
- rule: Pattern
216
- The route rule, example "/my/path"
217
220
path: str
218
221
The path of the route
222
+ rule: Pattern
223
+ The route rule, example "/my/path"
219
224
func: Callable
220
225
The route handler function
221
226
cors: bool
@@ -224,12 +229,20 @@ def __init__(
224
229
Whether or not to enable gzip compression for this route
225
230
cache_control: Optional[str]
226
231
The cache control header value, example "max-age=3600"
227
- middlewares : Optional[List[Callable[..., Response]] ]
228
- The list of route middlewares to be called in order.
232
+ summary : Optional[str ]
233
+ The OpenAPI summary for this route
229
234
description: Optional[str]
230
235
The OpenAPI description for this route
236
+ responses: Optional[Dict[Union[int, str], Dict[str, Any]]]
237
+ The OpenAPI responses for this route
238
+ response_description: Optional[str]
239
+ The OpenAPI response description for this route
231
240
tags: Optional[List[Tag]]
232
241
The list of OpenAPI tags to be used for this route
242
+ operation_id: Optional[str]
243
+ The OpenAPI operationId for this route
244
+ middlewares: Optional[List[Callable[..., Response]]]
245
+ The list of route middlewares to be called in order.
233
246
"""
234
247
self .method = method .upper ()
235
248
self .path = path
@@ -239,10 +252,13 @@ def __init__(
239
252
self .cors = cors
240
253
self .compress = compress
241
254
self .cache_control = cache_control
242
- self .middlewares = middlewares or []
255
+ self .summary = summary
243
256
self .description = description
257
+ self .responses = responses
258
+ self .response_description = response_description
244
259
self .tags = tags or []
245
- self .operation_id = self .method .title () + self .func .__name__ .title ()
260
+ self .middlewares = middlewares or []
261
+ self .operation_id = operation_id or (self .method .title () + self .func .__name__ .title ())
246
262
247
263
# _middleware_stack_built is used to ensure the middleware stack is only built once.
248
264
self ._middleware_stack_built = False
@@ -370,7 +386,7 @@ def _get_openapi_path(
370
386
371
387
responses = operation .setdefault ("responses" , {})
372
388
success_response = responses .setdefault ("200" , {})
373
- success_response ["description" ] = "Success"
389
+ success_response ["description" ] = self . response_description or _DEFAULT_OPENAPI_RESPONSE_DESCRIPTION
374
390
success_response ["content" ] = {"application/json" : {"schema" : {}}}
375
391
json_response = success_response ["content" ].setdefault ("application/json" , {})
376
392
@@ -389,7 +405,7 @@ def _get_openapi_path(
389
405
return path , definitions
390
406
391
407
def _openapi_operation_summary (self ) -> str :
392
- return f"{ self .method .upper ()} { self .path } "
408
+ return self . summary or f"{ self .method .upper ()} { self .path } "
393
409
394
410
def _openapi_operation_metadata (self , operation_ids : Set [str ]) -> Dict [str , Any ]:
395
411
operation : Dict [str , Any ] = {}
@@ -596,8 +612,12 @@ def route(
596
612
cors : Optional [bool ] = None ,
597
613
compress : bool = False ,
598
614
cache_control : Optional [str ] = None ,
615
+ summary : Optional [str ] = None ,
599
616
description : Optional [str ] = None ,
617
+ responses : Optional [Dict [Union [int , str ], Dict [str , Any ]]] = None ,
618
+ response_description : Optional [str ] = _DEFAULT_OPENAPI_RESPONSE_DESCRIPTION ,
600
619
tags : Optional [List ["Tag" ]] = None ,
620
+ operation_id : Optional [str ] = None ,
601
621
middlewares : Optional [List [Callable [..., Any ]]] = None ,
602
622
):
603
623
raise NotImplementedError ()
@@ -649,9 +669,13 @@ def get(
649
669
cors : Optional [bool ] = None ,
650
670
compress : bool = False ,
651
671
cache_control : Optional [str ] = None ,
652
- middlewares : Optional [List [ Callable [..., Any ]] ] = None ,
672
+ summary : Optional [str ] = None ,
653
673
description : Optional [str ] = None ,
674
+ responses : Optional [Dict [Union [int , str ], Dict [str , Any ]]] = None ,
675
+ response_description : Optional [str ] = _DEFAULT_OPENAPI_RESPONSE_DESCRIPTION ,
654
676
tags : Optional [List ["Tag" ]] = None ,
677
+ operation_id : Optional [str ] = None ,
678
+ middlewares : Optional [List [Callable [..., Any ]]] = None ,
655
679
):
656
680
"""Get route decorator with GET `method`
657
681
@@ -675,17 +699,34 @@ def lambda_handler(event, context):
675
699
return app.resolve(event, context)
676
700
```
677
701
"""
678
- return self .route (rule , "GET" , cors , compress , cache_control , description , tags , middlewares )
702
+ return self .route (
703
+ rule ,
704
+ "GET" ,
705
+ cors ,
706
+ compress ,
707
+ cache_control ,
708
+ summary ,
709
+ description ,
710
+ responses ,
711
+ response_description ,
712
+ tags ,
713
+ operation_id ,
714
+ middlewares ,
715
+ )
679
716
680
717
def post (
681
718
self ,
682
719
rule : str ,
683
720
cors : Optional [bool ] = None ,
684
721
compress : bool = False ,
685
722
cache_control : Optional [str ] = None ,
686
- middlewares : Optional [List [ Callable [..., Any ]] ] = None ,
723
+ summary : Optional [str ] = None ,
687
724
description : Optional [str ] = None ,
725
+ responses : Optional [Dict [Union [int , str ], Dict [str , Any ]]] = None ,
726
+ response_description : Optional [str ] = _DEFAULT_OPENAPI_RESPONSE_DESCRIPTION ,
688
727
tags : Optional [List ["Tag" ]] = None ,
728
+ operation_id : Optional [str ] = None ,
729
+ middlewares : Optional [List [Callable [..., Any ]]] = None ,
689
730
):
690
731
"""Post route decorator with POST `method`
691
732
@@ -710,17 +751,34 @@ def lambda_handler(event, context):
710
751
return app.resolve(event, context)
711
752
```
712
753
"""
713
- return self .route (rule , "POST" , cors , compress , cache_control , description , tags , middlewares )
754
+ return self .route (
755
+ rule ,
756
+ "POST" ,
757
+ cors ,
758
+ compress ,
759
+ cache_control ,
760
+ summary ,
761
+ description ,
762
+ responses ,
763
+ response_description ,
764
+ tags ,
765
+ operation_id ,
766
+ middlewares ,
767
+ )
714
768
715
769
def put (
716
770
self ,
717
771
rule : str ,
718
772
cors : Optional [bool ] = None ,
719
773
compress : bool = False ,
720
774
cache_control : Optional [str ] = None ,
721
- middlewares : Optional [List [ Callable [..., Any ]] ] = None ,
775
+ summary : Optional [str ] = None ,
722
776
description : Optional [str ] = None ,
777
+ responses : Optional [Dict [Union [int , str ], Dict [str , Any ]]] = None ,
778
+ response_description : Optional [str ] = _DEFAULT_OPENAPI_RESPONSE_DESCRIPTION ,
723
779
tags : Optional [List ["Tag" ]] = None ,
780
+ operation_id : Optional [str ] = None ,
781
+ middlewares : Optional [List [Callable [..., Any ]]] = None ,
724
782
):
725
783
"""Put route decorator with PUT `method`
726
784
@@ -745,17 +803,34 @@ def lambda_handler(event, context):
745
803
return app.resolve(event, context)
746
804
```
747
805
"""
748
- return self .route (rule , "PUT" , cors , compress , cache_control , description , tags , middlewares )
806
+ return self .route (
807
+ rule ,
808
+ "PUT" ,
809
+ cors ,
810
+ compress ,
811
+ cache_control ,
812
+ summary ,
813
+ description ,
814
+ responses ,
815
+ response_description ,
816
+ tags ,
817
+ operation_id ,
818
+ middlewares ,
819
+ )
749
820
750
821
def delete (
751
822
self ,
752
823
rule : str ,
753
824
cors : Optional [bool ] = None ,
754
825
compress : bool = False ,
755
826
cache_control : Optional [str ] = None ,
756
- middlewares : Optional [List [ Callable [..., Any ]] ] = None ,
827
+ summary : Optional [str ] = None ,
757
828
description : Optional [str ] = None ,
829
+ responses : Optional [Dict [Union [int , str ], Dict [str , Any ]]] = None ,
830
+ response_description : Optional [str ] = _DEFAULT_OPENAPI_RESPONSE_DESCRIPTION ,
758
831
tags : Optional [List ["Tag" ]] = None ,
832
+ operation_id : Optional [str ] = None ,
833
+ middlewares : Optional [List [Callable [..., Any ]]] = None ,
759
834
):
760
835
"""Delete route decorator with DELETE `method`
761
836
@@ -779,17 +854,34 @@ def lambda_handler(event, context):
779
854
return app.resolve(event, context)
780
855
```
781
856
"""
782
- return self .route (rule , "DELETE" , cors , compress , cache_control , description , tags , middlewares )
857
+ return self .route (
858
+ rule ,
859
+ "DELETE" ,
860
+ cors ,
861
+ compress ,
862
+ cache_control ,
863
+ summary ,
864
+ description ,
865
+ responses ,
866
+ response_description ,
867
+ tags ,
868
+ operation_id ,
869
+ middlewares ,
870
+ )
783
871
784
872
def patch (
785
873
self ,
786
874
rule : str ,
787
875
cors : Optional [bool ] = None ,
788
876
compress : bool = False ,
789
877
cache_control : Optional [str ] = None ,
790
- middlewares : Optional [List [ Callable ] ] = None ,
878
+ summary : Optional [str ] = None ,
791
879
description : Optional [str ] = None ,
880
+ responses : Optional [Dict [Union [int , str ], Dict [str , Any ]]] = None ,
881
+ response_description : Optional [str ] = _DEFAULT_OPENAPI_RESPONSE_DESCRIPTION ,
792
882
tags : Optional [List ["Tag" ]] = None ,
883
+ operation_id : Optional [str ] = None ,
884
+ middlewares : Optional [List [Callable ]] = None ,
793
885
):
794
886
"""Patch route decorator with PATCH `method`
795
887
@@ -816,7 +908,20 @@ def lambda_handler(event, context):
816
908
return app.resolve(event, context)
817
909
```
818
910
"""
819
- return self .route (rule , "PATCH" , cors , compress , cache_control , description , tags , middlewares )
911
+ return self .route (
912
+ rule ,
913
+ "PATCH" ,
914
+ cors ,
915
+ compress ,
916
+ cache_control ,
917
+ summary ,
918
+ description ,
919
+ responses ,
920
+ response_description ,
921
+ tags ,
922
+ operation_id ,
923
+ middlewares ,
924
+ )
820
925
821
926
def _push_processed_stack_frame (self , frame : str ):
822
927
"""
@@ -1202,8 +1307,12 @@ def route(
1202
1307
cors : Optional [bool ] = None ,
1203
1308
compress : bool = False ,
1204
1309
cache_control : Optional [str ] = None ,
1310
+ summary : Optional [str ] = None ,
1205
1311
description : Optional [str ] = None ,
1312
+ responses : Optional [Dict [Union [int , str ], Dict [str , Any ]]] = None ,
1313
+ response_description : Optional [str ] = _DEFAULT_OPENAPI_RESPONSE_DESCRIPTION ,
1206
1314
tags : Optional [List ["Tag" ]] = None ,
1315
+ operation_id : Optional [str ] = None ,
1207
1316
middlewares : Optional [List [Callable [..., Any ]]] = None ,
1208
1317
):
1209
1318
"""Route decorator includes parameter `method`"""
@@ -1223,9 +1332,13 @@ def register_resolver(func: Callable):
1223
1332
cors_enabled ,
1224
1333
compress ,
1225
1334
cache_control ,
1226
- middlewares ,
1335
+ summary ,
1227
1336
description ,
1337
+ responses ,
1338
+ response_description ,
1228
1339
tags ,
1340
+ operation_id ,
1341
+ middlewares ,
1229
1342
)
1230
1343
1231
1344
# The more specific route wins.
@@ -1623,15 +1736,31 @@ def route(
1623
1736
cors : Optional [bool ] = None ,
1624
1737
compress : bool = False ,
1625
1738
cache_control : Optional [str ] = None ,
1739
+ summary : Optional [str ] = None ,
1626
1740
description : Optional [str ] = None ,
1741
+ responses : Optional [Dict [Union [int , str ], Dict [str , Any ]]] = None ,
1742
+ response_description : Optional [str ] = _DEFAULT_OPENAPI_RESPONSE_DESCRIPTION ,
1627
1743
tags : Optional [List ["Tag" ]] = None ,
1744
+ operation_id : Optional [str ] = None ,
1628
1745
middlewares : Optional [List [Callable [..., Any ]]] = None ,
1629
1746
):
1630
1747
def register_route (func : Callable ):
1631
1748
# Convert methods to tuple. It needs to be hashable as its part of the self._routes dict key
1632
1749
methods = (method ,) if isinstance (method , str ) else tuple (method )
1633
1750
1634
- route_key = (rule , methods , cors , compress , cache_control , description , tags )
1751
+ route_key = (
1752
+ rule ,
1753
+ methods ,
1754
+ cors ,
1755
+ compress ,
1756
+ cache_control ,
1757
+ summary ,
1758
+ description ,
1759
+ responses ,
1760
+ response_description ,
1761
+ tags ,
1762
+ operation_id ,
1763
+ )
1635
1764
1636
1765
# Collate Middleware for routes
1637
1766
if middlewares is not None :
@@ -1671,12 +1800,29 @@ def route(
1671
1800
cors : Optional [bool ] = None ,
1672
1801
compress : bool = False ,
1673
1802
cache_control : Optional [str ] = None ,
1803
+ summary : Optional [str ] = None ,
1674
1804
description : Optional [str ] = None ,
1805
+ responses : Optional [Dict [Union [int , str ], Dict [str , Any ]]] = None ,
1806
+ response_description : Optional [str ] = _DEFAULT_OPENAPI_RESPONSE_DESCRIPTION ,
1675
1807
tags : Optional [List ["Tag" ]] = None ,
1808
+ operation_id : Optional [str ] = None ,
1676
1809
middlewares : Optional [List [Callable [..., Any ]]] = None ,
1677
1810
):
1678
1811
# NOTE: see #1552 for more context.
1679
- return super ().route (rule .rstrip ("/" ), method , cors , compress , cache_control , description , tags , middlewares )
1812
+ return super ().route (
1813
+ rule .rstrip ("/" ),
1814
+ method ,
1815
+ cors ,
1816
+ compress ,
1817
+ cache_control ,
1818
+ summary ,
1819
+ description ,
1820
+ responses ,
1821
+ response_description ,
1822
+ tags ,
1823
+ operation_id ,
1824
+ middlewares ,
1825
+ )
1680
1826
1681
1827
# Override _compile_regex to exclude trailing slashes for route resolution
1682
1828
@staticmethod
0 commit comments