mirror of https://github.com/tiangolo/fastapi.git
195 lines
8.8 KiB
Markdown
195 lines
8.8 KiB
Markdown
# OpenAPI-Callbacks
|
|
|
|
Sie könnten eine API mit einer *Pfadoperation* erstellen, die einen Request an eine *externe API* auslösen könnte, welche von jemand anderem erstellt wurde (wahrscheinlich derselbe Entwickler, der Ihre API *verwenden* würde).
|
|
|
|
Der Vorgang, der stattfindet, wenn Ihre API-Anwendung die *externe API* aufruft, wird als „Callback“ („Rückruf“) bezeichnet. Denn die Software, die der externe Entwickler geschrieben hat, sendet einen Request an Ihre API und dann *ruft Ihre API zurück* (*calls back*) und sendet einen Request an eine *externe API* (die wahrscheinlich vom selben Entwickler erstellt wurde).
|
|
|
|
In diesem Fall möchten Sie möglicherweise dokumentieren, wie diese externe API aussehen *sollte*. Welche *Pfadoperation* sie haben sollte, welchen Body sie erwarten sollte, welche Response sie zurückgeben sollte, usw.
|
|
|
|
## Eine Anwendung mit Callbacks
|
|
|
|
Sehen wir uns das alles anhand eines Beispiels an.
|
|
|
|
Stellen Sie sich vor, Sie entwickeln eine Anwendung, mit der Sie Rechnungen erstellen können.
|
|
|
|
Diese Rechnungen haben eine `id`, einen optionalen `title`, einen `customer` (Kunde) und ein `total` (Gesamtsumme).
|
|
|
|
Der Benutzer Ihrer API (ein externer Entwickler) erstellt mit einem POST-Request eine Rechnung in Ihrer API.
|
|
|
|
Dann wird Ihre API (beispielsweise):
|
|
|
|
* die Rechnung an einen Kunden des externen Entwicklers senden.
|
|
* das Geld einsammeln.
|
|
* eine Benachrichtigung an den API-Benutzer (den externen Entwickler) zurücksenden.
|
|
* Dies erfolgt durch Senden eines POST-Requests (von *Ihrer API*) an eine *externe API*, die von diesem externen Entwickler bereitgestellt wird (das ist der „Callback“).
|
|
|
|
## Die normale **FastAPI**-Anwendung
|
|
|
|
Sehen wir uns zunächst an, wie die normale API-Anwendung aussehen würde, bevor wir den Callback hinzufügen.
|
|
|
|
Sie verfügt über eine *Pfadoperation*, die einen `Invoice`-Body empfängt, und einen Query-Parameter `callback_url`, der die URL für den Callback enthält.
|
|
|
|
Dieser Teil ist ziemlich normal, der größte Teil des Codes ist Ihnen wahrscheinlich bereits bekannt:
|
|
|
|
```Python hl_lines="9-13 36-53"
|
|
{!../../docs_src/openapi_callbacks/tutorial001.py!}
|
|
```
|
|
|
|
/// tip | "Tipp"
|
|
|
|
Der Query-Parameter `callback_url` verwendet einen Pydantic-<a href="https://docs.pydantic.dev/latest/api/networks/" class="external-link" target="_blank">Url</a>-Typ.
|
|
|
|
///
|
|
|
|
Das einzig Neue ist `callbacks=invoices_callback_router.routes` als Argument für den *Pfadoperation-Dekorator*. Wir werden als Nächstes sehen, was das ist.
|
|
|
|
## Dokumentation des Callbacks
|
|
|
|
Der tatsächliche Callback-Code hängt stark von Ihrer eigenen API-Anwendung ab.
|
|
|
|
Und er wird wahrscheinlich von Anwendung zu Anwendung sehr unterschiedlich sein.
|
|
|
|
Es könnten nur eine oder zwei Codezeilen sein, wie zum Beispiel:
|
|
|
|
```Python
|
|
callback_url = "https://example.com/api/v1/invoices/events/"
|
|
httpx.post(callback_url, json={"description": "Invoice paid", "paid": True})
|
|
```
|
|
|
|
Der möglicherweise wichtigste Teil des Callbacks besteht jedoch darin, sicherzustellen, dass Ihr API-Benutzer (der externe Entwickler) die *externe API* gemäß den Daten, die *Ihre API* im Requestbody des Callbacks senden wird, korrekt implementiert, usw.
|
|
|
|
Als Nächstes fügen wir den Code hinzu, um zu dokumentieren, wie diese *externe API* aussehen sollte, um den Callback von *Ihrer API* zu empfangen.
|
|
|
|
Diese Dokumentation wird in der Swagger-Oberfläche unter `/docs` in Ihrer API angezeigt und zeigt externen Entwicklern, wie diese die *externe API* erstellen sollten.
|
|
|
|
In diesem Beispiel wird nicht der Callback selbst implementiert (das könnte nur eine Codezeile sein), sondern nur der Dokumentationsteil.
|
|
|
|
/// tip | "Tipp"
|
|
|
|
Der eigentliche Callback ist nur ein HTTP-Request.
|
|
|
|
Wenn Sie den Callback selbst implementieren, können Sie beispielsweise <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a> oder <a href="https://requests.readthedocs.io/" class="external-link" target="_blank">Requests</a> verwenden.
|
|
|
|
///
|
|
|
|
## Schreiben des Codes, der den Callback dokumentiert
|
|
|
|
Dieser Code wird nicht in Ihrer Anwendung ausgeführt, wir benötigen ihn nur, um zu *dokumentieren*, wie diese *externe API* aussehen soll.
|
|
|
|
Sie wissen jedoch bereits, wie Sie mit **FastAPI** ganz einfach eine automatische Dokumentation für eine API erstellen.
|
|
|
|
Daher werden wir dasselbe Wissen nutzen, um zu dokumentieren, wie die *externe API* aussehen sollte ... indem wir die *Pfadoperation(en)* erstellen, welche die externe API implementieren soll (die, welche Ihre API aufruft).
|
|
|
|
/// tip | "Tipp"
|
|
|
|
Wenn Sie den Code zum Dokumentieren eines Callbacks schreiben, kann es hilfreich sein, sich vorzustellen, dass Sie dieser *externe Entwickler* sind. Und dass Sie derzeit die *externe API* implementieren, nicht *Ihre API*.
|
|
|
|
Wenn Sie diese Sichtweise (des *externen Entwicklers*) vorübergehend übernehmen, wird es offensichtlicher, wo die Parameter, das Pydantic-Modell für den Body, die Response, usw. für diese *externe API* hingehören.
|
|
|
|
///
|
|
|
|
### Einen Callback-`APIRouter` erstellen
|
|
|
|
Erstellen Sie zunächst einen neuen `APIRouter`, der einen oder mehrere Callbacks enthält.
|
|
|
|
```Python hl_lines="3 25"
|
|
{!../../docs_src/openapi_callbacks/tutorial001.py!}
|
|
```
|
|
|
|
### Die Callback-*Pfadoperation* erstellen
|
|
|
|
Um die Callback-*Pfadoperation* zu erstellen, verwenden Sie denselben `APIRouter`, den Sie oben erstellt haben.
|
|
|
|
Sie sollte wie eine normale FastAPI-*Pfadoperation* aussehen:
|
|
|
|
* Sie sollte wahrscheinlich eine Deklaration des Bodys enthalten, die sie erhalten soll, z. B. `body: InvoiceEvent`.
|
|
* Und sie könnte auch eine Deklaration der Response enthalten, die zurückgegeben werden soll, z. B. `response_model=InvoiceEventReceived`.
|
|
|
|
```Python hl_lines="16-18 21-22 28-32"
|
|
{!../../docs_src/openapi_callbacks/tutorial001.py!}
|
|
```
|
|
|
|
Es gibt zwei Hauptunterschiede zu einer normalen *Pfadoperation*:
|
|
|
|
* Es muss kein tatsächlicher Code vorhanden sein, da Ihre Anwendung diesen Code niemals aufruft. Sie wird nur zur Dokumentation der *externen API* verwendet. Die Funktion könnte also einfach `pass` enthalten.
|
|
* Der *Pfad* kann einen <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression" class="external-link" target="_blank">OpenAPI-3-Ausdruck</a> enthalten (mehr dazu weiter unten), wo er Variablen mit Parametern und Teilen des ursprünglichen Requests verwenden kann, der an *Ihre API* gesendet wurde.
|
|
|
|
### Der Callback-Pfadausdruck
|
|
|
|
Der Callback-*Pfad* kann einen <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression" class="external-link" target="_blank">OpenAPI-3-Ausdruck</a> enthalten, welcher Teile des ursprünglichen Requests enthalten kann, der an *Ihre API* gesendet wurde.
|
|
|
|
In diesem Fall ist es der `str`:
|
|
|
|
```Python
|
|
"{$callback_url}/invoices/{$request.body.id}"
|
|
```
|
|
|
|
Wenn Ihr API-Benutzer (der externe Entwickler) also einen Request an *Ihre API* sendet, via:
|
|
|
|
```
|
|
https://yourapi.com/invoices/?callback_url=https://www.external.org/events
|
|
```
|
|
|
|
mit einem JSON-Körper:
|
|
|
|
```JSON
|
|
{
|
|
"id": "2expen51ve",
|
|
"customer": "Mr. Richie Rich",
|
|
"total": "9999"
|
|
}
|
|
```
|
|
|
|
dann verarbeitet *Ihre API* die Rechnung und sendet irgendwann später einen Callback-Request an die `callback_url` (die *externe API*):
|
|
|
|
```
|
|
https://www.external.org/events/invoices/2expen51ve
|
|
```
|
|
|
|
mit einem JSON-Body, der etwa Folgendes enthält:
|
|
|
|
```JSON
|
|
{
|
|
"description": "Payment celebration",
|
|
"paid": true
|
|
}
|
|
```
|
|
|
|
und sie würde eine Response von dieser *externen API* mit einem JSON-Body wie dem folgenden erwarten:
|
|
|
|
```JSON
|
|
{
|
|
"ok": true
|
|
}
|
|
```
|
|
|
|
/// tip | "Tipp"
|
|
|
|
Beachten Sie, dass die verwendete Callback-URL die URL enthält, die als Query-Parameter in `callback_url` (`https://www.external.org/events`) empfangen wurde, und auch die Rechnungs-`id` aus dem JSON-Body (`2expen51ve`).
|
|
|
|
///
|
|
|
|
### Den Callback-Router hinzufügen
|
|
|
|
An diesem Punkt haben Sie die benötigte(n) *Callback-Pfadoperation(en)* (diejenige(n), die der *externe Entwickler* in der *externen API* implementieren sollte) im Callback-Router, den Sie oben erstellt haben.
|
|
|
|
Verwenden Sie nun den Parameter `callbacks` im *Pfadoperation-Dekorator Ihrer API*, um das Attribut `.routes` (das ist eigentlich nur eine `list`e von Routen/*Pfadoperationen*) dieses Callback-Routers zu übergeben:
|
|
|
|
```Python hl_lines="35"
|
|
{!../../docs_src/openapi_callbacks/tutorial001.py!}
|
|
```
|
|
|
|
/// tip | "Tipp"
|
|
|
|
Beachten Sie, dass Sie nicht den Router selbst (`invoices_callback_router`) an `callback=` übergeben, sondern das Attribut `.routes`, wie in `invoices_callback_router.routes`.
|
|
|
|
///
|
|
|
|
### Es in der Dokumentation ansehen
|
|
|
|
Jetzt können Sie Ihre Anwendung mit Uvicorn starten und auf <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> gehen.
|
|
|
|
Sie sehen Ihre Dokumentation, einschließlich eines Abschnitts „Callbacks“ für Ihre *Pfadoperation*, der zeigt, wie die *externe API* aussehen sollte:
|
|
|
|
<img src="/img/tutorial/openapi-callbacks/image01.png">
|