1
from typing import Optional
3
from dirty_equals import IsDict
4
from fastapi import APIRouter, FastAPI
5
from fastapi.testclient import TestClient
6
from pydantic import BaseModel, HttpUrl
11
class Invoice(BaseModel):
13
title: Optional[str] = None
18
class InvoiceEvent(BaseModel):
23
class InvoiceEventReceived(BaseModel):
27
invoices_callback_router = APIRouter()
30
@invoices_callback_router.post(
31
"{$callback_url}/invoices/{$request.body.id}", response_model=InvoiceEventReceived
33
def invoice_notification(body: InvoiceEvent):
37
class Event(BaseModel):
42
events_callback_router = APIRouter()
45
@events_callback_router.get("{$callback_url}/events/{$request.body.title}")
46
def event_callback(event: Event):
50
subrouter = APIRouter()
53
@subrouter.post("/invoices/", callbacks=invoices_callback_router.routes)
54
def create_invoice(invoice: Invoice, callback_url: Optional[HttpUrl] = None):
58
This will (let's imagine) let the API user (some external developer) create an
61
And this path operation will:
63
* Send the invoice to the client.
64
* Collect the money from the client.
65
* Send a notification back to the API user (the external developer), as a callback.
66
* At this point is that the API will somehow send a POST request to the
67
external API with the notification of the invoice event
68
(e.g. "payment successful").
71
return {"msg": "Invoice received"}
74
app.include_router(subrouter, callbacks=events_callback_router.routes)
76
client = TestClient(app)
80
response = client.post(
81
"/invoices/", json={"id": "fooinvoice", "customer": "John", "total": 5.3}
83
assert response.status_code == 200, response.text
84
assert response.json() == {"msg": "Invoice received"}
87
def test_openapi_schema():
89
response = client.get("/openapi.json")
90
assert response.json() == {
92
"info": {"title": "FastAPI", "version": "0.1.0"},
96
"summary": "Create Invoice",
97
"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").',
98
"operationId": "create_invoice_invoices__post",
104
"title": "Callback Url",
119
"title": "Callback Url",
126
"name": "callback_url",
132
"application/json": {
133
"schema": {"$ref": "#/components/schemas/Invoice"}
140
"description": "Successful Response",
141
"content": {"application/json": {"schema": {}}},
144
"description": "Validation Error",
146
"application/json": {
148
"$ref": "#/components/schemas/HTTPValidationError"
156
"{$callback_url}/events/{$request.body.title}": {
158
"summary": "Event Callback",
159
"operationId": "event_callback__callback_url__events___request_body_title__get",
163
"application/json": {
165
"$ref": "#/components/schemas/Event"
172
"description": "Successful Response",
174
"application/json": {"schema": {}}
178
"description": "Validation Error",
180
"application/json": {
182
"$ref": "#/components/schemas/HTTPValidationError"
191
"invoice_notification": {
192
"{$callback_url}/invoices/{$request.body.id}": {
194
"summary": "Invoice Notification",
195
"operationId": "invoice_notification__callback_url__invoices___request_body_id__post",
199
"application/json": {
201
"$ref": "#/components/schemas/InvoiceEvent"
208
"description": "Successful Response",
210
"application/json": {
212
"$ref": "#/components/schemas/InvoiceEventReceived"
218
"description": "Validation Error",
220
"application/json": {
222
"$ref": "#/components/schemas/HTTPValidationError"
239
"required": ["name", "total"],
242
"name": {"title": "Name", "type": "string"},
243
"total": {"title": "Total", "type": "number"},
246
"HTTPValidationError": {
247
"title": "HTTPValidationError",
254
"$ref": "#/components/schemas/ValidationError"
261
"required": ["id", "customer", "total"],
264
"id": {"title": "Id", "type": "string"},
268
"anyOf": [{"type": "string"}, {"type": "null"}],
273
{"title": "Title", "type": "string"}
275
"customer": {"title": "Customer", "type": "string"},
276
"total": {"title": "Total", "type": "number"},
280
"title": "InvoiceEvent",
281
"required": ["description", "paid"],
284
"description": {"title": "Description", "type": "string"},
285
"paid": {"title": "Paid", "type": "boolean"},
288
"InvoiceEventReceived": {
289
"title": "InvoiceEventReceived",
292
"properties": {"ok": {"title": "Ok", "type": "boolean"}},
295
"title": "ValidationError",
296
"required": ["loc", "msg", "type"],
303
"anyOf": [{"type": "string"}, {"type": "integer"}]
306
"msg": {"title": "Message", "type": "string"},
307
"type": {"title": "Error Type", "type": "string"},