From 73260971b5a1499c92e70aa11a96c406497a1f14 Mon Sep 17 00:00:00 2001 From: Ben Dayan Date: Wed, 11 Dec 2019 18:58:01 +0200 Subject: [PATCH] :sparkles: Add support for OpenAPI Callbacks (#722) --- .../tutorial/openapi-callbacks/image01.png | Bin 0 -> 99295 bytes docs/src/openapi_callbacks/tutorial001.py | 53 +++++ docs/tutorial/openapi-callbacks.md | 186 ++++++++++++++++++ fastapi/applications.py | 16 ++ fastapi/openapi/utils.py | 8 + fastapi/routing.py | 44 ++++- fastapi/utils.py | 7 +- mkdocs.yml | 1 + tests/test_application.py | 40 ++-- tests/test_extra_routes.py | 2 +- tests/test_starlette_exception.py | 2 +- .../test_tutorial009.py | 2 +- .../test_extra_models/test_tutorial005.py | 4 +- .../test_handling_errors/test_tutorial002.py | 2 +- .../test_openapi_callbacks/__init__.py | 0 .../test_tutorial001.py | 174 ++++++++++++++++ 16 files changed, 503 insertions(+), 38 deletions(-) create mode 100644 docs/img/tutorial/openapi-callbacks/image01.png create mode 100644 docs/src/openapi_callbacks/tutorial001.py create mode 100644 docs/tutorial/openapi-callbacks.md create mode 100644 tests/test_tutorial/test_openapi_callbacks/__init__.py create mode 100644 tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py diff --git a/docs/img/tutorial/openapi-callbacks/image01.png b/docs/img/tutorial/openapi-callbacks/image01.png new file mode 100644 index 0000000000000000000000000000000000000000..45e6366ab939da5963ef710555da435d91ff47ab GIT binary patch literal 99295 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%0Dvu6 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 literal 0 HcmV?d00001 diff --git a/docs/src/openapi_callbacks/tutorial001.py b/docs/src/openapi_callbacks/tutorial001.py new file mode 100644 index 000000000..b2838b0a2 --- /dev/null +++ b/docs/src/openapi_callbacks/tutorial001.py @@ -0,0 +1,53 @@ +from fastapi import APIRouter, FastAPI +from pydantic import BaseModel, HttpUrl +from starlette.responses import JSONResponse + +app = FastAPI() + + +class Invoice(BaseModel): + id: str + title: str = None + customer: str + total: float + + +class InvoiceEvent(BaseModel): + description: str + paid: bool + + +class InvoiceEventReceived(BaseModel): + ok: bool + + +invoices_callback_router = APIRouter(default_response_class=JSONResponse) + + +@invoices_callback_router.post( + "{$callback_url}/invoices/{$request.body.id}", + response_model=InvoiceEventReceived, +) +def invoice_notification(body: InvoiceEvent): + pass + + +@app.post("/invoices/", callbacks=invoices_callback_router.routes) +def create_invoice(invoice: Invoice, callback_url: HttpUrl = None): + """ + Create an invoice. + + This will (let's imagine) let the API user (some external developer) create an + invoice. + + And this path operation will: + + * Send the invoice to the client. + * Collect the money from the client. + * Send a notification back to the API user (the external developer), as a callback. + * At this point is that the API will somehow send a POST request to the + external API with the notification of the invoice event + (e.g. "payment successful"). + """ + # Send the invoice, collect the money, send the notification (the callback) + return {"msg": "Invoice received"} diff --git a/docs/tutorial/openapi-callbacks.md b/docs/tutorial/openapi-callbacks.md new file mode 100644 index 000000000..e48ee7f95 --- /dev/null +++ b/docs/tutorial/openapi-callbacks.md @@ -0,0 +1,186 @@ +You could create an API with a *path operation* that could trigger a request to an *external API* created by someone else (probably the same developer that would be *using* your API). + +The process that happens when your API app calls the *external API* is named a "callback". Because the software that the external developer wrote sends a request to your API and then your API *calls back*, sending a request to an *external API* (that was probably created by the same developer). + +In this case, you could want to document how that external API *should* look like. What *path operation* it should have, what body it should expect, what response it should return, etc. + +## An app with callbacks + +Let's see all this with an example. + +Imagine you develop an app that allows creating invoices. + +These invoices will have an `id`, `title` (optional), `customer`, and `total`. + +The user of your API (an external developer) will create an invoice in your API with a POST request. + +Then your API will (let's imagine): + +* Send the invoice to some customer of the external developer. +* Collect the money. +* Send a notification back to the API user (the external developer). + * This will be done by sending a POST request (from *your API*) to some *external API* provided by that external developer (this is the "callback"). + +## The normal **FastAPI** app + +Let's first see how the normal API app would look like before adding the callback. + +It will have a *path operation* that will receive an `Invoice` body, and a query parameter `callback_url` that will contain the URL for the callback. + +This part is pretty normal, most of the code is probably already familiar to you: + +```Python hl_lines="8 9 10 11 12 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54" +{!./src/openapi_callbacks/tutorial001.py!} +``` + +!!! tip + The `callback_url` query parameter uses a Pydantic URL type. + +The only new thing is the `callbacks=messages_callback_router.routes` as an argument to the *path operation decorator*. We'll see what that is next. + +## Documenting the callback + +The actual callback code will depend heavily on your own API app. + +And it will probably vary a lot from one app to the next. + +It could be just one or two lines of code, like: + +```Python +callback_url = "https://example.com/api/v1/invoices/events/" +requests.post(callback_url, json={"description": "Invoice paid", "paid": True}) +``` + +But possibly the most important part of the callback is making sure that your API user (the external developer) implements the *external API* correctly, according to the data that *your API* is going to send in the request body of the callback, etc. + +So, what we will do next is add the code to document how that *external API* should look like to receive the callback from *your API*. + +That documentation will show up in the Swagger UI at `/docs` in your API, and it will let external developers know how to build the *external API*. + +This example doesn't implement the callback itself (that could be just a line of code), only the documentation part. + +!!! tip + The actual callback is just an HTTP request. + + When implementing the callback yourself, you could use something like HTTPX or Requests. + +## Write the callback documentation code + +This code won't be executed in your app, we only need it to *document* how that *external API* should look like. + +But, you already know how to easily create automatic documentation for an API with **FastAPI**. + +So we are going to use that same knowledge to document how the *external API* should look like... by creating the *path operation(s)* that the external API should implement (the ones your API will call). + +!!! tip + When writing the code to document a callback, it might be useful to imagine that you are that *external developer*. And that you are currently implementing the *external API*, not *your API*. + + Temporarily adopting this point of view (of the *external developer*) can help you feel like it's more obvious where to put the parameters, the Pydantic model for the body, for the response, etc. for that *external API*. + +### Create a callback `APIRouter` + +First create a new `APIRouter` that will contain one or more callbacks. + +This router will never be added to an actual `FastAPI` app (i.e. it will never be passed to `app.include_router(...)`). + +Because of that, you need to declare what will be the `default_response_class`, and set it to `JSONResponse`. + +!!! Note "Technical Details" + The `response_class` is normally set by the `FastAPI` app during the call to `app.include_router(some_router)`. + + But as we are never calling `app.include_router(some_router)`, we need to set the `default_response_class` during creation of the `APIRouter`. + +```Python hl_lines="3 24" +{!./src/openapi_callbacks/tutorial001.py!} +``` + +### Create the callback *path operation* + +To create the callback *path operation* use the same `APIRouter` you created above. + +It should look just like a normal FastAPI *path operation*: + +* It should probably have a declaration of the body it should receive, e.g. `body: InvoiceEvent`. +* And it could also have a declaration of the response it should return, e.g. `response_model=InvoiceEventReceived`. + +```Python hl_lines="15 16 17 20 21 27 28 29 30 31 32" +{!./src/openapi_callbacks/tutorial001.py!} +``` + +There are 2 main differences from a normal *path operation*: + +* It doesn't need to have any actual code, because your app will never call this code. It's only used to document the *external API*. So, the function could just have `pass`. +* The *path* can contain an OpenAPI 3 expression (see more below) where it can use variables with parameters and parts of the original request sent to *your API*. + +### The callback path expression + +The callback *path* can have an OpenAPI 3 expression that can contain parts of the original request sent to *your API*. + +In this case, it's the `str`: + +```Python +"{$callback_url}/invoices/{$request.body.id}" +``` + +So, if your API user (the external developer) sends a request to *your API* to: + +``` +https://yourapi.com/invoices/?callback_url=https://www.external.org/events +``` + +with a JSON body of: + +```JSON +{ + "id": "2expen51ve", + "customer": "Mr. Richie Rich", + "total": "9999" +} +``` + +Then *your API* will process the invoice, and at some point later, send a callback request to the `callback_url` (the *external API*): + +``` +https://www.external.org/events/invoices/2expen51ve +``` + +with a JSON body containing something like: + +```JSON +{ + "description": "Payment celebration", + "paid": true +} +``` + +and it would expect a response from that *external API* with a JSON body like: + +```JSON +{ + "ok": true +} +``` + +!!! tip + Notice how the callback URL used contains the URL received as a query parameter in `callback_url` (`https://www.external.org/events`) and also the invoice `id` from inside of the JSON body (`2expen51ve`). + +### Add the callback router + +At this point you have the *callback path operation(s)* needed (the one(s) that the *external developer* should implement in the *external API*) in the callback router you created above. + +Now use the parameter `callbacks` in *your API's path operation decorator* to pass the attribute `.routes` (that's actually just a `list` of routes/*path operations*) from that callback router: + +```Python hl_lines="35" +{!./src/openapi_callbacks/tutorial001.py!} +``` + +!!! tip + Notice that you are not passing the router itself (`invoices_callback_router`) to `callback=`, but the attribute `.routes`, as in `invoices_callback_router.routes`. + +### Check the docs + +Now you can start your app with Uvicorn and go to http://127.0.0.1:8000/docs. + +You will see your docs including a "Callback" section for your *path operation* that shows how the *external API* should look like: + + diff --git a/fastapi/applications.py b/fastapi/applications.py index ab1b77e6d..5a533866b 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -303,6 +303,7 @@ class FastAPI(Starlette): include_in_schema: bool = True, response_class: Type[Response] = None, name: str = None, + callbacks: List[routing.APIRoute] = None, ) -> Callable: if response_model_skip_defaults is not None: warning_response_model_skip_defaults_deprecated() # pragma: nocover @@ -327,6 +328,7 @@ class FastAPI(Starlette): include_in_schema=include_in_schema, response_class=response_class or self.default_response_class, name=name, + callbacks=callbacks, ) def put( @@ -351,6 +353,7 @@ class FastAPI(Starlette): include_in_schema: bool = True, response_class: Type[Response] = None, name: str = None, + callbacks: List[routing.APIRoute] = None, ) -> Callable: if response_model_skip_defaults is not None: warning_response_model_skip_defaults_deprecated() # pragma: nocover @@ -375,6 +378,7 @@ class FastAPI(Starlette): include_in_schema=include_in_schema, response_class=response_class or self.default_response_class, name=name, + callbacks=callbacks, ) def post( @@ -399,6 +403,7 @@ class FastAPI(Starlette): include_in_schema: bool = True, response_class: Type[Response] = None, name: str = None, + callbacks: List[routing.APIRoute] = None, ) -> Callable: if response_model_skip_defaults is not None: warning_response_model_skip_defaults_deprecated() # pragma: nocover @@ -423,6 +428,7 @@ class FastAPI(Starlette): include_in_schema=include_in_schema, response_class=response_class or self.default_response_class, name=name, + callbacks=callbacks, ) def delete( @@ -447,6 +453,7 @@ class FastAPI(Starlette): include_in_schema: bool = True, response_class: Type[Response] = None, name: str = None, + callbacks: List[routing.APIRoute] = None, ) -> Callable: if response_model_skip_defaults is not None: warning_response_model_skip_defaults_deprecated() # pragma: nocover @@ -471,6 +478,7 @@ class FastAPI(Starlette): include_in_schema=include_in_schema, response_class=response_class or self.default_response_class, name=name, + callbacks=callbacks, ) def options( @@ -495,6 +503,7 @@ class FastAPI(Starlette): include_in_schema: bool = True, response_class: Type[Response] = None, name: str = None, + callbacks: List[routing.APIRoute] = None, ) -> Callable: if response_model_skip_defaults is not None: warning_response_model_skip_defaults_deprecated() # pragma: nocover @@ -519,6 +528,7 @@ class FastAPI(Starlette): include_in_schema=include_in_schema, response_class=response_class or self.default_response_class, name=name, + callbacks=callbacks, ) def head( @@ -543,6 +553,7 @@ class FastAPI(Starlette): include_in_schema: bool = True, response_class: Type[Response] = None, name: str = None, + callbacks: List[routing.APIRoute] = None, ) -> Callable: if response_model_skip_defaults is not None: warning_response_model_skip_defaults_deprecated() # pragma: nocover @@ -567,6 +578,7 @@ class FastAPI(Starlette): include_in_schema=include_in_schema, response_class=response_class or self.default_response_class, name=name, + callbacks=callbacks, ) def patch( @@ -591,6 +603,7 @@ class FastAPI(Starlette): include_in_schema: bool = True, response_class: Type[Response] = None, name: str = None, + callbacks: List[routing.APIRoute] = None, ) -> Callable: if response_model_skip_defaults is not None: warning_response_model_skip_defaults_deprecated() # pragma: nocover @@ -615,6 +628,7 @@ class FastAPI(Starlette): include_in_schema=include_in_schema, response_class=response_class or self.default_response_class, name=name, + callbacks=callbacks, ) def trace( @@ -639,6 +653,7 @@ class FastAPI(Starlette): include_in_schema: bool = True, response_class: Type[Response] = None, name: str = None, + callbacks: List[routing.APIRoute] = None, ) -> Callable: if response_model_skip_defaults is not None: warning_response_model_skip_defaults_deprecated() # pragma: nocover @@ -663,4 +678,5 @@ class FastAPI(Starlette): include_in_schema=include_in_schema, response_class=response_class or self.default_response_class, name=name, + callbacks=callbacks, ) diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index d2dd62081..d53ee6b97 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -187,6 +187,14 @@ def get_openapi_path( ) if request_body_oai: operation["requestBody"] = request_body_oai + if route.callbacks: + callbacks = {} + for callback in route.callbacks: + cb_path, cb_security_schemes, cb_definitions, = get_openapi_path( + route=callback, model_name_map=model_name_map + ) + callbacks[callback.name] = {callback.path: cb_path} + operation["callbacks"] = callbacks if route.responses: for (additional_status_code, response) in route.responses.items(): assert isinstance( diff --git a/fastapi/routing.py b/fastapi/routing.py index 8f4c67ca5..ee75374b4 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -218,6 +218,7 @@ class APIRoute(routing.Route): include_in_schema: bool = True, response_class: Optional[Type[Response]] = None, dependency_overrides_provider: Any = None, + callbacks: Optional[List["APIRoute"]] = None, ) -> None: self.path = path self.endpoint = endpoint @@ -338,6 +339,7 @@ class APIRoute(routing.Route): ) self.body_field = get_body_field(dependant=self.dependant, name=self.unique_id) self.dependency_overrides_provider = dependency_overrides_provider + self.callbacks = callbacks self.app = request_response(self.get_route_handler()) def get_route_handler(self) -> Callable: @@ -363,12 +365,14 @@ class APIRouter(routing.Router): default: ASGIApp = None, dependency_overrides_provider: Any = None, route_class: Type[APIRoute] = APIRoute, + default_response_class: Type[Response] = None, ) -> None: super().__init__( routes=routes, redirect_slashes=redirect_slashes, default=default ) self.dependency_overrides_provider = dependency_overrides_provider self.route_class = route_class + self.default_response_class = default_response_class def add_api_route( self, @@ -395,6 +399,7 @@ class APIRouter(routing.Router): response_class: Type[Response] = None, name: str = None, route_class_override: Optional[Type[APIRoute]] = None, + callbacks: List[APIRoute] = None, ) -> None: if response_model_skip_defaults is not None: warning_response_model_skip_defaults_deprecated() # pragma: nocover @@ -420,9 +425,10 @@ class APIRouter(routing.Router): response_model_exclude_unset or response_model_skip_defaults ), include_in_schema=include_in_schema, - response_class=response_class, + response_class=response_class or self.default_response_class, name=name, dependency_overrides_provider=self.dependency_overrides_provider, + callbacks=callbacks, ) self.routes.append(route) @@ -449,6 +455,7 @@ class APIRouter(routing.Router): include_in_schema: bool = True, response_class: Type[Response] = None, name: str = None, + callbacks: List[APIRoute] = None, ) -> Callable: if response_model_skip_defaults is not None: warning_response_model_skip_defaults_deprecated() # pragma: nocover @@ -475,8 +482,9 @@ class APIRouter(routing.Router): response_model_exclude_unset or response_model_skip_defaults ), include_in_schema=include_in_schema, - response_class=response_class, + response_class=response_class or self.default_response_class, name=name, + callbacks=callbacks, ) return func @@ -586,6 +594,7 @@ class APIRouter(routing.Router): include_in_schema: bool = True, response_class: Type[Response] = None, name: str = None, + callbacks: List[APIRoute] = None, ) -> Callable: if response_model_skip_defaults is not None: warning_response_model_skip_defaults_deprecated() # pragma: nocover @@ -609,8 +618,9 @@ class APIRouter(routing.Router): response_model_exclude_unset or response_model_skip_defaults ), include_in_schema=include_in_schema, - response_class=response_class, + response_class=response_class or self.default_response_class, name=name, + callbacks=callbacks, ) def put( @@ -635,6 +645,7 @@ class APIRouter(routing.Router): include_in_schema: bool = True, response_class: Type[Response] = None, name: str = None, + callbacks: List[APIRoute] = None, ) -> Callable: if response_model_skip_defaults is not None: warning_response_model_skip_defaults_deprecated() # pragma: nocover @@ -658,8 +669,9 @@ class APIRouter(routing.Router): response_model_exclude_unset or response_model_skip_defaults ), include_in_schema=include_in_schema, - response_class=response_class, + response_class=response_class or self.default_response_class, name=name, + callbacks=callbacks, ) def post( @@ -684,6 +696,7 @@ class APIRouter(routing.Router): include_in_schema: bool = True, response_class: Type[Response] = None, name: str = None, + callbacks: List[APIRoute] = None, ) -> Callable: if response_model_skip_defaults is not None: warning_response_model_skip_defaults_deprecated() # pragma: nocover @@ -707,8 +720,9 @@ class APIRouter(routing.Router): response_model_exclude_unset or response_model_skip_defaults ), include_in_schema=include_in_schema, - response_class=response_class, + response_class=response_class or self.default_response_class, name=name, + callbacks=callbacks, ) def delete( @@ -733,6 +747,7 @@ class APIRouter(routing.Router): include_in_schema: bool = True, response_class: Type[Response] = None, name: str = None, + callbacks: List[APIRoute] = None, ) -> Callable: if response_model_skip_defaults is not None: warning_response_model_skip_defaults_deprecated() # pragma: nocover @@ -756,8 +771,9 @@ class APIRouter(routing.Router): response_model_exclude_unset or response_model_skip_defaults ), include_in_schema=include_in_schema, - response_class=response_class, + response_class=response_class or self.default_response_class, name=name, + callbacks=callbacks, ) def options( @@ -782,6 +798,7 @@ class APIRouter(routing.Router): include_in_schema: bool = True, response_class: Type[Response] = None, name: str = None, + callbacks: List[APIRoute] = None, ) -> Callable: if response_model_skip_defaults is not None: warning_response_model_skip_defaults_deprecated() # pragma: nocover @@ -805,8 +822,9 @@ class APIRouter(routing.Router): response_model_exclude_unset or response_model_skip_defaults ), include_in_schema=include_in_schema, - response_class=response_class, + response_class=response_class or self.default_response_class, name=name, + callbacks=callbacks, ) def head( @@ -831,6 +849,7 @@ class APIRouter(routing.Router): include_in_schema: bool = True, response_class: Type[Response] = None, name: str = None, + callbacks: List[APIRoute] = None, ) -> Callable: if response_model_skip_defaults is not None: warning_response_model_skip_defaults_deprecated() # pragma: nocover @@ -854,8 +873,9 @@ class APIRouter(routing.Router): response_model_exclude_unset or response_model_skip_defaults ), include_in_schema=include_in_schema, - response_class=response_class, + response_class=response_class or self.default_response_class, name=name, + callbacks=callbacks, ) def patch( @@ -880,6 +900,7 @@ class APIRouter(routing.Router): include_in_schema: bool = True, response_class: Type[Response] = None, name: str = None, + callbacks: List[APIRoute] = None, ) -> Callable: if response_model_skip_defaults is not None: warning_response_model_skip_defaults_deprecated() # pragma: nocover @@ -903,8 +924,9 @@ class APIRouter(routing.Router): response_model_exclude_unset or response_model_skip_defaults ), include_in_schema=include_in_schema, - response_class=response_class, + response_class=response_class or self.default_response_class, name=name, + callbacks=callbacks, ) def trace( @@ -929,6 +951,7 @@ class APIRouter(routing.Router): include_in_schema: bool = True, response_class: Type[Response] = None, name: str = None, + callbacks: List[APIRoute] = None, ) -> Callable: if response_model_skip_defaults is not None: warning_response_model_skip_defaults_deprecated() # pragma: nocover @@ -952,6 +975,7 @@ class APIRouter(routing.Router): response_model_exclude_unset or response_model_skip_defaults ), include_in_schema=include_in_schema, - response_class=response_class, + response_class=response_class or self.default_response_class, name=name, + callbacks=callbacks, ) diff --git a/fastapi/utils.py b/fastapi/utils.py index 5e624f0ea..a068cc582 100644 --- a/fastapi/utils.py +++ b/fastapi/utils.py @@ -46,6 +46,7 @@ def warning_response_model_skip_defaults_deprecated() -> None: def get_flat_models_from_routes(routes: Sequence[BaseRoute]) -> Set[Type[BaseModel]]: body_fields_from_routes: List[ModelField] = [] responses_from_routes: List[ModelField] = [] + callback_flat_models: Set[Type[BaseModel]] = set() for route in routes: if getattr(route, "include_in_schema", None) and isinstance( route, routing.APIRoute @@ -59,7 +60,9 @@ def get_flat_models_from_routes(routes: Sequence[BaseRoute]) -> Set[Type[BaseMod responses_from_routes.append(route.response_field) if route.response_fields: responses_from_routes.extend(route.response_fields.values()) - flat_models = get_flat_models_from_fields( + if route.callbacks: + callback_flat_models |= get_flat_models_from_routes(route.callbacks) + flat_models = callback_flat_models | get_flat_models_from_fields( body_fields_from_routes + responses_from_routes, known_models=set() ) return flat_models @@ -153,6 +156,6 @@ def create_cloned_field(field: ModelField) -> ModelField: def generate_operation_id_for_path(*, name: str, path: str, method: str) -> str: operation_id = name + path - operation_id = operation_id.replace("{", "_").replace("}", "_").replace("/", "_") + operation_id = re.sub("[^0-9a-zA-Z_]", "_", operation_id) operation_id = operation_id + "_" + method.lower() return operation_id diff --git a/mkdocs.yml b/mkdocs.yml index d458366a7..541afc8e8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -88,6 +88,7 @@ nav: - Testing Dependencies with Overrides: 'tutorial/testing-dependencies.md' - Debugging: 'tutorial/debugging.md' - Extending OpenAPI: 'tutorial/extending-openapi.md' + - OpenAPI Callbacks: 'tutorial/openapi-callbacks.md' - Concurrency and async / await: 'async.md' - Deployment: 'deployment.md' - Project Generation - Template: 'project-generation.md' diff --git a/tests/test_application.py b/tests/test_application.py index bdbff1cf6..11f463336 100644 --- a/tests/test_application.py +++ b/tests/test_application.py @@ -244,7 +244,7 @@ openapi_schema = { }, }, "summary": "Get Path Param Required Id", - "operationId": "get_path_param_required_id_path_param-required__item_id__get", + "operationId": "get_path_param_required_id_path_param_required__item_id__get", "parameters": [ { "required": True, @@ -274,7 +274,7 @@ openapi_schema = { }, }, "summary": "Get Path Param Min Length", - "operationId": "get_path_param_min_length_path_param-minlength__item_id__get", + "operationId": "get_path_param_min_length_path_param_minlength__item_id__get", "parameters": [ { "required": True, @@ -308,7 +308,7 @@ openapi_schema = { }, }, "summary": "Get Path Param Max Length", - "operationId": "get_path_param_max_length_path_param-maxlength__item_id__get", + "operationId": "get_path_param_max_length_path_param_maxlength__item_id__get", "parameters": [ { "required": True, @@ -342,7 +342,7 @@ openapi_schema = { }, }, "summary": "Get Path Param Min Max Length", - "operationId": "get_path_param_min_max_length_path_param-min_maxlength__item_id__get", + "operationId": "get_path_param_min_max_length_path_param_min_maxlength__item_id__get", "parameters": [ { "required": True, @@ -377,7 +377,7 @@ openapi_schema = { }, }, "summary": "Get Path Param Gt", - "operationId": "get_path_param_gt_path_param-gt__item_id__get", + "operationId": "get_path_param_gt_path_param_gt__item_id__get", "parameters": [ { "required": True, @@ -411,7 +411,7 @@ openapi_schema = { }, }, "summary": "Get Path Param Gt0", - "operationId": "get_path_param_gt0_path_param-gt0__item_id__get", + "operationId": "get_path_param_gt0_path_param_gt0__item_id__get", "parameters": [ { "required": True, @@ -445,7 +445,7 @@ openapi_schema = { }, }, "summary": "Get Path Param Ge", - "operationId": "get_path_param_ge_path_param-ge__item_id__get", + "operationId": "get_path_param_ge_path_param_ge__item_id__get", "parameters": [ { "required": True, @@ -479,7 +479,7 @@ openapi_schema = { }, }, "summary": "Get Path Param Lt", - "operationId": "get_path_param_lt_path_param-lt__item_id__get", + "operationId": "get_path_param_lt_path_param_lt__item_id__get", "parameters": [ { "required": True, @@ -513,7 +513,7 @@ openapi_schema = { }, }, "summary": "Get Path Param Lt0", - "operationId": "get_path_param_lt0_path_param-lt0__item_id__get", + "operationId": "get_path_param_lt0_path_param_lt0__item_id__get", "parameters": [ { "required": True, @@ -547,7 +547,7 @@ openapi_schema = { }, }, "summary": "Get Path Param Le", - "operationId": "get_path_param_le_path_param-le__item_id__get", + "operationId": "get_path_param_le_path_param_le__item_id__get", "parameters": [ { "required": True, @@ -581,7 +581,7 @@ openapi_schema = { }, }, "summary": "Get Path Param Lt Gt", - "operationId": "get_path_param_lt_gt_path_param-lt-gt__item_id__get", + "operationId": "get_path_param_lt_gt_path_param_lt_gt__item_id__get", "parameters": [ { "required": True, @@ -616,7 +616,7 @@ openapi_schema = { }, }, "summary": "Get Path Param Le Ge", - "operationId": "get_path_param_le_ge_path_param-le-ge__item_id__get", + "operationId": "get_path_param_le_ge_path_param_le_ge__item_id__get", "parameters": [ { "required": True, @@ -651,7 +651,7 @@ openapi_schema = { }, }, "summary": "Get Path Param Lt Int", - "operationId": "get_path_param_lt_int_path_param-lt-int__item_id__get", + "operationId": "get_path_param_lt_int_path_param_lt_int__item_id__get", "parameters": [ { "required": True, @@ -685,7 +685,7 @@ openapi_schema = { }, }, "summary": "Get Path Param Gt Int", - "operationId": "get_path_param_gt_int_path_param-gt-int__item_id__get", + "operationId": "get_path_param_gt_int_path_param_gt_int__item_id__get", "parameters": [ { "required": True, @@ -719,7 +719,7 @@ openapi_schema = { }, }, "summary": "Get Path Param Le Int", - "operationId": "get_path_param_le_int_path_param-le-int__item_id__get", + "operationId": "get_path_param_le_int_path_param_le_int__item_id__get", "parameters": [ { "required": True, @@ -753,7 +753,7 @@ openapi_schema = { }, }, "summary": "Get Path Param Ge Int", - "operationId": "get_path_param_ge_int_path_param-ge-int__item_id__get", + "operationId": "get_path_param_ge_int_path_param_ge_int__item_id__get", "parameters": [ { "required": True, @@ -787,7 +787,7 @@ openapi_schema = { }, }, "summary": "Get Path Param Lt Gt Int", - "operationId": "get_path_param_lt_gt_int_path_param-lt-gt-int__item_id__get", + "operationId": "get_path_param_lt_gt_int_path_param_lt_gt_int__item_id__get", "parameters": [ { "required": True, @@ -822,7 +822,7 @@ openapi_schema = { }, }, "summary": "Get Path Param Le Ge Int", - "operationId": "get_path_param_le_ge_int_path_param-le-ge-int__item_id__get", + "operationId": "get_path_param_le_ge_int_path_param_le_ge_int__item_id__get", "parameters": [ { "required": True, @@ -1037,7 +1037,7 @@ openapi_schema = { }, }, "summary": "Get Query Param Required", - "operationId": "get_query_param_required_query_param-required_get", + "operationId": "get_query_param_required_query_param_required_get", "parameters": [ { "required": True, @@ -1067,7 +1067,7 @@ openapi_schema = { }, }, "summary": "Get Query Param Required Type", - "operationId": "get_query_param_required_type_query_param-required_int_get", + "operationId": "get_query_param_required_type_query_param_required_int_get", "parameters": [ { "required": True, diff --git a/tests/test_extra_routes.py b/tests/test_extra_routes.py index f5bd7b3f2..bfe79d77f 100644 --- a/tests/test_extra_routes.py +++ b/tests/test_extra_routes.py @@ -259,7 +259,7 @@ openapi_schema = { }, }, "summary": "Get Not Decorated", - "operationId": "get_not_decorated_items-not-decorated__item_id__get", + "operationId": "get_not_decorated_items_not_decorated__item_id__get", "parameters": [ { "required": True, diff --git a/tests/test_starlette_exception.py b/tests/test_starlette_exception.py index 706957b99..bafa31835 100644 --- a/tests/test_starlette_exception.py +++ b/tests/test_starlette_exception.py @@ -80,7 +80,7 @@ openapi_schema = { }, }, "summary": "Create Item", - "operationId": "create_item_starlette-items__item_id__get", + "operationId": "create_item_starlette_items__item_id__get", "parameters": [ { "required": True, diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial009.py b/tests/test_tutorial/test_body_nested_models/test_tutorial009.py index e88e7a94a..d51b07252 100644 --- a/tests/test_tutorial/test_body_nested_models/test_tutorial009.py +++ b/tests/test_tutorial/test_body_nested_models/test_tutorial009.py @@ -27,7 +27,7 @@ openapi_schema = { }, }, "summary": "Create Index Weights", - "operationId": "create_index_weights_index-weights__post", + "operationId": "create_index_weights_index_weights__post", "requestBody": { "content": { "application/json": { diff --git a/tests/test_tutorial/test_extra_models/test_tutorial005.py b/tests/test_tutorial/test_extra_models/test_tutorial005.py index 7f815e08a..935debf92 100644 --- a/tests/test_tutorial/test_extra_models/test_tutorial005.py +++ b/tests/test_tutorial/test_extra_models/test_tutorial005.py @@ -16,7 +16,7 @@ openapi_schema = { "content": { "application/json": { "schema": { - "title": "Response Read Keyword Weights Keyword-Weights Get", + "title": "Response Read Keyword Weights Keyword Weights Get", "type": "object", "additionalProperties": {"type": "number"}, } @@ -25,7 +25,7 @@ openapi_schema = { } }, "summary": "Read Keyword Weights", - "operationId": "read_keyword_weights_keyword-weights__get", + "operationId": "read_keyword_weights_keyword_weights__get", } } }, diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial002.py b/tests/test_tutorial/test_handling_errors/test_tutorial002.py index 3381f9d72..e0aa05a15 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial002.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial002.py @@ -27,7 +27,7 @@ openapi_schema = { }, }, "summary": "Read Item Header", - "operationId": "read_item_header_items-header__item_id__get", + "operationId": "read_item_header_items_header__item_id__get", "parameters": [ { "required": True, diff --git a/tests/test_tutorial/test_openapi_callbacks/__init__.py b/tests/test_tutorial/test_openapi_callbacks/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py b/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py new file mode 100644 index 000000000..febbe7479 --- /dev/null +++ b/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py @@ -0,0 +1,174 @@ +from starlette.testclient import TestClient + +from openapi_callbacks.tutorial001 import app, invoice_notification + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "Fast API", "version": "0.1.0"}, + "paths": { + "/invoices/": { + "post": { + "summary": "Create Invoice", + "description": 'Create an invoice.\n\nThis will (let\'s imagine) let the API user (some external developer) create an\ninvoice.\n\nAnd this path operation will:\n\n* Send the invoice to the client.\n* Collect the money from the client.\n* Send a notification back to the API user (the external developer), as a callback.\n * At this point is that the API will somehow send a POST request to the\n external API with the notification of the invoice event\n (e.g. "payment successful").', + "operationId": "create_invoice_invoices__post", + "parameters": [ + { + "required": False, + "schema": { + "title": "Callback Url", + "maxLength": 2083, + "minLength": 1, + "type": "string", + "format": "uri", + }, + "name": "callback_url", + "in": "query", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Invoice"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "callbacks": { + "invoice_notification": { + "{$callback_url}/invoices/{$request.body.id}": { + "post": { + "summary": "Invoice Notification", + "operationId": "invoice_notification__callback_url__invoices___request_body_id__post", + "requestBody": { + "required": True, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvoiceEvent" + } + } + }, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvoiceEventReceived" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + } + }, + } + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Invoice": { + "title": "Invoice", + "required": ["id", "customer", "total"], + "type": "object", + "properties": { + "id": {"title": "Id", "type": "string"}, + "title": {"title": "Title", "type": "string"}, + "customer": {"title": "Customer", "type": "string"}, + "total": {"title": "Total", "type": "number"}, + }, + }, + "InvoiceEvent": { + "title": "InvoiceEvent", + "required": ["description", "paid"], + "type": "object", + "properties": { + "description": {"title": "Description", "type": "string"}, + "paid": {"title": "Paid", "type": "boolean"}, + }, + }, + "InvoiceEventReceived": { + "title": "InvoiceEventReceived", + "required": ["ok"], + "type": "object", + "properties": {"ok": {"title": "Ok", "type": "boolean"}}, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, +} + + +def test_openapi(): + with client: + response = client.get("/openapi.json") + + assert response.json() == openapi_schema + + +def test_get(): + response = client.post( + "/invoices/", json={"id": "fooinvoice", "customer": "John", "total": 5.3} + ) + assert response.status_code == 200 + assert response.json() == {"msg": "Invoice received"} + + +def test_dummy_callback(): + # Just for coverage + invoice_notification({})