Skip to content

Commit 06f0d2b

Browse files
authored
Merge pull request #420 from jnu/419/callbacks
419 / Support for parsing callbacks
2 parents 002ab32 + 82f6b87 commit 06f0d2b

File tree

1 file changed

+45
-1
lines changed

1 file changed

+45
-1
lines changed

fastapi_code_generator/parser.py

+45-1
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ class Operation(CachedPropertyModel):
123123
response: str = ''
124124
additional_responses: Dict[Union[str, int], Dict[str, str]] = {}
125125
return_type: str = ''
126+
callbacks: Dict[UsefulStr, List["Operation"]] = {}
126127

127128
@cached_property
128129
def type(self) -> UsefulStr:
@@ -472,10 +473,53 @@ def parse_operation(
472473
self._temporary_operation['snake_case_arguments'] = self.get_arguments(
473474
snake_case=True, path=path
474475
)
476+
main_operation = self._temporary_operation
477+
478+
# Handle callbacks. This iterates over callbacks, shifting each one
479+
# into the `_temporary_operation` and parsing it. Parsing could be
480+
# refactored into a recursive operation to simplify this routine.
481+
cb_ctr = 0
482+
callbacks: Dict[UsefulStr, list[Operation]] = {}
483+
if 'callbacks' in raw_operation:
484+
raw_callbacks = raw_operation.pop('callbacks')
485+
for key, routes in raw_callbacks.items():
486+
if key not in callbacks:
487+
callbacks[key] = []
488+
for route, methods in routes.items():
489+
for method, cb_op in methods.items():
490+
# Since the path is often generated dynamically from
491+
# the contents of the original request (such as by
492+
# passing a `callbackUrl`), it won't work to generate
493+
# a function name from the path. Instead, inject a
494+
# placeholder `operationId` in order to get a unique
495+
# and reasonable function name for the operation.
496+
if 'operationId' not in cb_op:
497+
cb_op['operationId'] = f"{method}_{key}_{cb_ctr}"
498+
cb_ctr += 1
499+
500+
self._temporary_operation = {'_parameters': []}
501+
cb_path = path + ['callbacks', key, route, method]
502+
super().parse_operation(cb_op, cb_path)
503+
self._temporary_operation['arguments'] = self.get_arguments(
504+
snake_case=False, path=cb_path
505+
)
506+
self._temporary_operation['snake_case_arguments'] = (
507+
self.get_arguments(snake_case=True, path=cb_path)
508+
)
509+
510+
callbacks[key].append(
511+
Operation(
512+
**cb_op,
513+
**self._temporary_operation,
514+
path=route,
515+
method=method, # type: ignore
516+
)
517+
)
475518

476519
self.operations[resolved_path] = Operation(
477520
**raw_operation,
478-
**self._temporary_operation,
521+
**main_operation,
522+
callbacks=callbacks,
479523
path=f'/{path_name}', # type: ignore
480524
method=method, # type: ignore
481525
)

0 commit comments

Comments
 (0)