Callbacks de OpenAPI¶
🌐 Traducción por IA y humanos
Esta traducción fue hecha por IA guiada por humanos. 🤝
Podría tener errores al interpretar el significado original, o sonar poco natural, etc. 🤖
Puedes mejorar esta traducciónayudándonos a guiar mejor al LLM de IA.
Podrías crear una API con unapath operation que podría desencadenar un request a unaAPI externa creada por alguien más (probablemente el mismo desarrollador que estaríausando tu API).
El proceso que ocurre cuando tu aplicación API llama a laAPI externa se llama un "callback". Porque el software que escribió el desarrollador externo envía un request a tu API y luego tu API hace uncallback, enviando un request a unaAPI externa (que probablemente fue creada por el mismo desarrollador).
En este caso, podrías querer documentar cómo esa API externadebería verse. Quépath operation debería tener, qué cuerpo debería esperar, qué response debería devolver, etc.
Una aplicación con callbacks¶
Veamos todo esto con un ejemplo.
Imagina que desarrollas una aplicación que permite crear facturas.
Estas facturas tendrán unid,title (opcional),customer ytotal.
El usuario de tu API (un desarrollador externo) creará una factura en tu API con un request POST.
Luego tu API (imaginemos):
- Enviará la factura a algún cliente del desarrollador externo.
- Recogerá el dinero.
- Enviará una notificación de vuelta al usuario de la API (el desarrollador externo).
- Esto se hará enviando un request POST (desdetu API) a algunaAPI externa proporcionada por ese desarrollador externo (este es el "callback").
La aplicación normal deFastAPI¶
Primero veamos cómo se vería la aplicación API normal antes de agregar el callback.
Tendrá unapath operation que recibirá un cuerpoInvoice, y un parámetro de querycallback_url que contendrá la URL para el callback.
Esta parte es bastante normal, probablemente ya estés familiarizado con la mayor parte del código:
fromfastapiimportAPIRouter,FastAPIfrompydanticimportBaseModel,HttpUrlapp=FastAPI()classInvoice(BaseModel):id:strtitle:str|None=Nonecustomer:strtotal:floatclassInvoiceEvent(BaseModel):description:strpaid:boolclassInvoiceEventReceived(BaseModel):ok:boolinvoices_callback_router=APIRouter()@invoices_callback_router.post("{$callback_url}/invoices/{$request.body.id}",response_model=InvoiceEventReceived)definvoice_notification(body:InvoiceEvent):pass@app.post("/invoices/",callbacks=invoices_callback_router.routes)defcreate_invoice(invoice:Invoice,callback_url:HttpUrl|None=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"}Consejo
El parámetro de querycallback_url utiliza un tipoUrl de Pydantic.
Lo único nuevo escallbacks=invoices_callback_router.routes como un argumento para eldecorador de path operation. Veremos qué es eso a continuación.
Documentar el callback¶
El código real del callback dependerá mucho de tu propia aplicación API.
Y probablemente variará mucho de una aplicación a otra.
Podría ser solo una o dos líneas de código, como:
callback_url="https://example.com/api/v1/invoices/events/"httpx.post(callback_url,json={"description":"Invoice paid","paid":True})Pero posiblemente la parte más importante del callback es asegurarse de que el usuario de tu API (el desarrollador externo) implemente laAPI externa correctamente, de acuerdo con los datos quetu API va a enviar en el request body del callback, etc.
Así que, lo que haremos a continuación es agregar el código para documentar cómo debería verse esaAPI externa para recibir el callback detu API.
Esa documentación aparecerá en la Swagger UI en/docs en tu API, y permitirá a los desarrolladores externos saber cómo construir laAPI externa.
Este ejemplo no implementa el callback en sí (eso podría ser solo una línea de código), solo la parte de documentación.
Consejo
El callback real es solo un request HTTP.
Cuando implementes el callback tú mismo, podrías usar algo comoHTTPX oRequests.
Escribe el código de documentación del callback¶
Este código no se ejecutará en tu aplicación, solo lo necesitamos paradocumentar cómo debería verse esaAPI externa.
Pero ya sabes cómo crear fácilmente documentación automática para una API conFastAPI.
Así que vamos a usar ese mismo conocimiento para documentar cómo debería verse laAPI externa... creando la(s)path operation(s) que la API externa debería implementar (las que tu API va a llamar).
Consejo
Cuando escribas el código para documentar un callback, podría ser útil imaginar que eres esedesarrollador externo. Y que actualmente estás implementando laAPI externa, notu API.
Adoptar temporalmente este punto de vista (deldesarrollador externo) puede ayudarte a sentir que es más obvio dónde poner los parámetros, el modelo de Pydantic para el body, para el response, etc. para esaAPI externa.
Crea unAPIRouter de callback¶
Primero crea un nuevoAPIRouter que contendrá uno o más callbacks.
fromfastapiimportAPIRouter,FastAPIfrompydanticimportBaseModel,HttpUrlapp=FastAPI()classInvoice(BaseModel):id:strtitle:str|None=Nonecustomer:strtotal:floatclassInvoiceEvent(BaseModel):description:strpaid:boolclassInvoiceEventReceived(BaseModel):ok:boolinvoices_callback_router=APIRouter()@invoices_callback_router.post("{$callback_url}/invoices/{$request.body.id}",response_model=InvoiceEventReceived)definvoice_notification(body:InvoiceEvent):pass@app.post("/invoices/",callbacks=invoices_callback_router.routes)defcreate_invoice(invoice:Invoice,callback_url:HttpUrl|None=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"}Crea lapath operation del callback¶
Para crear lapath operation del callback usa el mismoAPIRouter que creaste arriba.
Debería verse como unapath operation normal de FastAPI:
- Probablemente debería tener una declaración del body que debería recibir, por ejemplo
body: InvoiceEvent. - Y también podría tener una declaración del response que debería devolver, por ejemplo
response_model=InvoiceEventReceived.
fromfastapiimportAPIRouter,FastAPIfrompydanticimportBaseModel,HttpUrlapp=FastAPI()classInvoice(BaseModel):id:strtitle:str|None=Nonecustomer:strtotal:floatclassInvoiceEvent(BaseModel):description:strpaid:boolclassInvoiceEventReceived(BaseModel):ok:boolinvoices_callback_router=APIRouter()@invoices_callback_router.post("{$callback_url}/invoices/{$request.body.id}",response_model=InvoiceEventReceived)definvoice_notification(body:InvoiceEvent):pass@app.post("/invoices/",callbacks=invoices_callback_router.routes)defcreate_invoice(invoice:Invoice,callback_url:HttpUrl|None=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"}Hay 2 diferencias principales respecto a unapath operation normal:
- No necesita tener ningún código real, porque tu aplicación nunca llamará a este código. Solo se usa para documentar laAPI externa. Así que, la función podría simplemente tener
pass. - Elpath puede contener unaexpresión OpenAPI 3 (ver más abajo) donde puede usar variables con parámetros y partes del request original enviado atu API.
La expresión del path del callback¶
Elpath del callback puede tener unaexpresión OpenAPI 3 que puede contener partes del request original enviado atu API.
En este caso, es elstr:
"{$callback_url}/invoices/{$request.body.id}"Entonces, si el usuario de tu API (el desarrollador externo) envía un request atu API a:
https://yourapi.com/invoices/?callback_url=https://www.external.org/eventscon un JSON body de:
{"id":"2expen51ve","customer":"Mr. Richie Rich","total":"9999"}luegotu API procesará la factura y, en algún momento después, enviará un request de callback alcallback_url (laAPI externa):
https://www.external.org/events/invoices/2expen51vecon un JSON body que contiene algo como:
{"description":"Payment celebration","paid":true}y esperaría un response de esaAPI externa con un JSON body como:
{"ok":true}Consejo
Observa cómo la URL del callback utilizada contiene la URL recibida como parámetro de query encallback_url (https://www.external.org/events) y también elid de la factura desde dentro del JSON body (2expen51ve).
Agrega el router de callback¶
En este punto tienes laspath operation(s) del callback necesarias (las que eldesarrollador externo debería implementar en laAPI externa) en el router de callback que creaste arriba.
Ahora usa el parámetrocallbacks en eldecorador de path operation de tu API para pasar el atributo.routes (que en realidad es solo unlist de rutas/path operations) de ese router de callback:
fromfastapiimportAPIRouter,FastAPIfrompydanticimportBaseModel,HttpUrlapp=FastAPI()classInvoice(BaseModel):id:strtitle:str|None=Nonecustomer:strtotal:floatclassInvoiceEvent(BaseModel):description:strpaid:boolclassInvoiceEventReceived(BaseModel):ok:boolinvoices_callback_router=APIRouter()@invoices_callback_router.post("{$callback_url}/invoices/{$request.body.id}",response_model=InvoiceEventReceived)definvoice_notification(body:InvoiceEvent):pass@app.post("/invoices/",callbacks=invoices_callback_router.routes)defcreate_invoice(invoice:Invoice,callback_url:HttpUrl|None=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"}Consejo
Observa que no estás pasando el router en sí (invoices_callback_router) acallback=, sino el atributo.routes, como eninvoices_callback_router.routes.
Revisa la documentación¶
Ahora puedes iniciar tu aplicación e ir ahttp://127.0.0.1:8000/docs.
Verás tu documentación incluyendo una sección de "Callbacks" para tupath operation que muestra cómo debería verse laAPI externa:








