Co-authored-by: pr-submit[bot] <pr-submit[bot]@users.noreply.github.com> Co-authored-by: Yurii Motov <109919500+YuriiMotov@users.noreply.github.com> Co-authored-by: pr-push[bot] <pr-push[bot]@users.noreply.github.com>
13 KiB
OpenAPI Callbacks
рдЖрдк рдПрдХ рдРрд╕реА API рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ рдЬрд┐рд╕рдореЗрдВ рдПрдХ path operation рд╣реЛ рдЬреЛ рдХрд┐рд╕реА рдФрд░ рдХреЗ рджреНрд╡рд╛рд░рд╛ рдмрдирд╛рдИ рдЧрдИ external API рдХреЛ request trigger рдХрд░ рд╕рдХреЗ (рд╢рд╛рдпрдж рд╡рд╣реА developer рдЬреЛ рдЖрдкрдХреА API рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдЧрд╛)ред
рдЬрдм рдЖрдкрдХреА API app external API рдХреЛ call рдХрд░рддреА рд╣реИ, рдЙрд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ "callback" рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рдХреНрдпреЛрдВрдХрд┐ external developer рджреНрд╡рд╛рд░рд╛ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ software рдЖрдкрдХреА API рдХреЛ request рднреЗрдЬрддрд╛ рд╣реИ рдФрд░ рдлрд┐рд░ рдЖрдкрдХреА API call back рдХрд░рддреА рд╣реИ, рдпрд╛рдиреА рдХрд┐рд╕реА external API рдХреЛ request рднреЗрдЬрддреА рд╣реИ (рдЬреЛ рд╢рд╛рдпрдж рдЙрд╕реА developer рджреНрд╡рд╛рд░рд╛ рдмрдирд╛рдИ рдЧрдИ рдереА)ред
рдЗрд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ, рдЖрдк рдпрд╣ document рдХрд░рдирд╛ рдЪрд╛рд╣ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╡рд╣ external API рдХреИрд╕реА рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдПред рдЙрд╕рдореЗрдВ рдХреМрди-рд╕рд╛ path operation рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП, рдЙрд╕реЗ рдХреМрди-рд╕рд╛ body expect рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП, рдЙрд╕реЗ рдХреМрди-рд╕рд╛ response рд▓реМрдЯрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рдЖрджрд┐ред
Callbacks рд╡рд╛рд▓реА рдПрдХ app
рдЖрдЗрдП рдЗрд╕реЗ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд╕рд╛рде рджреЗрдЦрддреЗ рд╣реИрдВред
рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ рдХрд┐ рдЖрдк рдПрдХ рдРрд╕реА app develop рдХрд░рддреЗ рд╣реИрдВ рдЬреЛ invoices рдмрдирд╛рдиреЗ рджреЗрддреА рд╣реИред
рдЗрди invoices рдореЗрдВ рдПрдХ id, title (optional), customer, рдФрд░ total рд╣реЛрдЧрд╛ред
рдЖрдкрдХреА API рдХрд╛ user (рдПрдХ external developer) рдЖрдкрдХреА API рдореЗрдВ POST request рдХреЗ рд╕рд╛рде рдПрдХ invoice рдмрдирд╛рдПрдЧрд╛ред
рдлрд┐рд░ рдЖрдкрдХреА API (рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ):
- invoice рдХреЛ external developer рдХреЗ рдХрд┐рд╕реА customer рдХреЛ рднреЗрдЬреЗрдЧреАред
- рдкреИрд╕реЗ collect рдХрд░реЗрдЧреАред
- API user (external developer) рдХреЛ рд╡рд╛рдкрд╕ рдПрдХ notification рднреЗрдЬреЗрдЧреАред
- рдпрд╣ (рдЖрдкрдХреА API рд╕реЗ) рдЙрд╕ external developer рджреНрд╡рд╛рд░рд╛ рджреА рдЧрдИ рдХрд┐рд╕реА external API рдХреЛ POST request рднреЗрдЬрдХрд░ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ (рдпрд╣реА "callback" рд╣реИ)ред
рд╕рд╛рдорд╛рдиреНрдп FastAPI app
Callback рдЬреЛрдбрд╝рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, рдкрд╣рд▓реЗ рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐ рд╕рд╛рдорд╛рдиреНрдп API app рдХреИрд╕реА рджрд┐рдЦреЗрдЧреАред
рдЗрд╕рдореЗрдВ рдПрдХ path operation рд╣реЛрдЧрд╛ рдЬреЛ рдПрдХ Invoice body receive рдХрд░реЗрдЧрд╛, рдФрд░ рдПрдХ query parameter callback_url рд╣реЛрдЧрд╛ рдЬрд┐рд╕рдореЗрдВ callback рдХреЗ рд▓рд┐рдП URL рд╣реЛрдЧрд╛ред
рдпрд╣ рд╣рд┐рд╕реНрд╕рд╛ рдХрд╛рдлрд╝реА рд╕рд╛рдорд╛рдиреНрдп рд╣реИ, рдЕрдзрд┐рдХрддрд░ code рд╢рд╛рдпрдж рдЖрдкрдХреЛ рдкрд╣рд▓реЗ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реЛрдЧрд╛:
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *}
/// tip | рд╕реБрдЭрд╛рд╡
callback_url query parameter рдПрдХ Pydantic Url type рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред
///
рдХреЗрд╡рд▓ рдирдИ рдЪреАрдЬрд╝ рд╣реИ path operation decorator рдХреЗ argument рдХреЗ рд░реВрдк рдореЗрдВ callbacks=invoices_callback_router.routesред рдЖрдЧреЗ рд╣рдо рджреЗрдЦреЗрдВрдЧреЗ рдХрд┐ рдпрд╣ рдХреНрдпрд╛ рд╣реИред
Callback рдХреЛ document рдХрд░рдирд╛
рд╡рд╛рд╕реНрддрд╡рд┐рдХ callback code рдЖрдкрдХреА рдЕрдкрдиреА API app рдкрд░ рдмрд╣реБрдд рдЕрдзрд┐рдХ рдирд┐рд░реНрднрд░ рдХрд░реЗрдЧрд╛ред
рдФрд░ рдпрд╣ рдПрдХ app рд╕реЗ рджреВрд╕рд░реА app рдореЗрдВ рдХрд╛рдлрд╝реА рдЕрд▓рдЧ рд╣реЛ рд╕рдХрддрд╛ рд╣реИред
рдпрд╣ code рдХреА рд╕рд┐рд░реНрдлрд╝ рдПрдХ рдпрд╛ рджреЛ lines рднреА рд╣реЛ рд╕рдХрддреА рд╣реИрдВ, рдЬреИрд╕реЗ:
callback_url = "https://example.com/api/v1/invoices/events/"
httpx.post(callback_url, json={"description": "Invoice paid", "paid": True})
рд▓реЗрдХрд┐рди рд╕рдВрднрд╡рддрдГ callback рдХрд╛ рд╕рдмрд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣рд┐рд╕реНрд╕рд╛ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдирд╛ рд╣реИ рдХрд┐ рдЖрдкрдХрд╛ API user (external developer) external API рдХреЛ рд╕рд╣реА рддрд░рд╣ рд╕реЗ implement рдХрд░реЗ, рдЙрд╕ data рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдЬрд┐рд╕реЗ рдЖрдкрдХреА API callback рдХреЗ request body рдореЗрдВ рднреЗрдЬрдиреЗ рд╡рд╛рд▓реА рд╣реИ, рдЖрджрд┐ред
рддреЛ, рдЕрдм рд╣рдо рд╡рд╣ code рдЬреЛрдбрд╝реЗрдВрдЧреЗ рдЬреЛ document рдХрд░реЗрдЧрд╛ рдХрд┐ рдЖрдкрдХреА API рд╕реЗ callback receive рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд╣ external API рдХреИрд╕реА рджрд┐рдЦрдиреА рдЪрд╛рд╣рд┐рдПред
рдпрд╣ documentation рдЖрдкрдХреА API рдореЗрдВ /docs рдкрд░ Swagger UI рдореЗрдВ рджрд┐рдЦрд╛рдИ рджреЗрдЧреА, рдФрд░ рдпрд╣ external developers рдХреЛ рдмрддрд╛рдПрдЧреА рдХрд┐ external API рдХреИрд╕реЗ рдмрдирд╛рдиреА рд╣реИред
рдпрд╣ рдЙрджрд╛рд╣рд░рдг callback рдХреЛ рд╕реНрд╡рдпрдВ implement рдирд╣реАрдВ рдХрд░рддрд╛ (рд╡рд╣ рдХреЗрд╡рд▓ code рдХреА рдПрдХ line рд╣реЛ рд╕рдХрддреА рд╣реИ), рдХреЗрд╡рд▓ documentation рд╡рд╛рд▓рд╛ рд╣рд┐рд╕реНрд╕рд╛ рдХрд░рддрд╛ рд╣реИред
/// tip | рд╕реБрдЭрд╛рд╡
рд╡рд╛рд╕реНрддрд╡рд┐рдХ callback рд╕рд┐рд░реНрдлрд╝ рдПрдХ HTTP request рд╣реИред
Callback рдХреЛ рд╕реНрд╡рдпрдВ implement рдХрд░рддреЗ рд╕рдордп, рдЖрдк HTTPX рдпрд╛ Requests рдЬреИрд╕реА рдХрд┐рд╕реА рдЪреАрдЬрд╝ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
///
Callback documentation code рд▓рд┐рдЦреЗрдВ
рдпрд╣ code рдЖрдкрдХреА app рдореЗрдВ execute рдирд╣реАрдВ рд╣реЛрдЧрд╛, рд╣рдореЗрдВ рдЗрд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗрд╡рд▓ рдпрд╣ document рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИ рдХрд┐ рд╡рд╣ external API рдХреИрд╕реА рджрд┐рдЦрдиреА рдЪрд╛рд╣рд┐рдПред
рд▓реЗрдХрд┐рди, рдЖрдк рдкрд╣рд▓реЗ рд╕реЗ рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ FastAPI рдХреЗ рд╕рд╛рде рдХрд┐рд╕реА API рдХреЗ рд▓рд┐рдП automatic documentation рдЖрд╕рд╛рдиреА рд╕реЗ рдХреИрд╕реЗ рдмрдирд╛рдИ рдЬрд╛рддреА рд╣реИред
рдЗрд╕рд▓рд┐рдП рд╣рдо рдЙрд╕реА рдЬреНрдЮрд╛рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ document рдХрд░реЗрдВрдЧреЗ рдХрд┐ external API рдХреИрд╕реА рджрд┐рдЦрдиреА рдЪрд╛рд╣рд┐рдП... рдЙрди path operation(s) рдХреЛ рдмрдирд╛рдХрд░ рдЬрд┐рдиреНрд╣реЗрдВ external API рдХреЛ implement рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП (рдЬрд┐рдиреНрд╣реЗрдВ рдЖрдкрдХреА API call рдХрд░реЗрдЧреА)ред
/// tip | рд╕реБрдЭрд╛рд╡
Callback рдХреЛ document рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП code рд▓рд┐рдЦрддреЗ рд╕рдордп, рдпрд╣ рдХрд▓реНрдкрдирд╛ рдХрд░рдирд╛ рдЙрдкрдпреЛрдЧреА рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдЖрдк рд╡рд╣реА external developer рд╣реИрдВред рдФрд░ рдЗрд╕ рд╕рдордп рдЖрдк external API implement рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдЕрдкрдиреА API рдирд╣реАрдВред
рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЛ рдЕрд╕реНрдерд╛рдпреА рд░реВрдк рд╕реЗ рдЕрдкрдирд╛рдирд╛ (external developer рдХрд╛) рдЖрдкрдХреЛ рдпрд╣ рдЕрдзрд┐рдХ рд╕реНрдкрд╖реНрдЯ рдорд╣рд╕реВрд╕ рдХрд░рд╛рдиреЗ рдореЗрдВ рдорджрдж рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдЙрд╕ external API рдХреЗ рд▓рд┐рдП parameters, body рдХреЗ рд▓рд┐рдП Pydantic model, response рдХреЗ рд▓рд┐рдП model, рдЖрджрд┐ рдХрд╣рд╛рдБ рд░рдЦрдиреЗ рд╣реИрдВред
///
Callback APIRouter рдмрдирд╛рдПрдБ
рдкрд╣рд▓реЗ рдПрдХ рдирдпрд╛ APIRouter рдмрдирд╛рдПрдБ рдЬрд┐рд╕рдореЗрдВ рдПрдХ рдпрд╛ рдЕрдзрд┐рдХ callbacks рд╣реЛрдВрдЧреЗред
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *}
Callback path operation рдмрдирд╛рдПрдБ
Callback path operation рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд╣реА APIRouter рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ рдЬреЛ рдЖрдкрдиреЗ рдКрдкрд░ рдмрдирд╛рдпрд╛ рдерд╛ред
рдпрд╣ рдмрд┐рд▓реНрдХреБрд▓ рд╕рд╛рдорд╛рдиреНрдп FastAPI path operation рдЬреИрд╕рд╛ рджрд┐рдЦрдирд╛ рдЪрд╛рд╣рд┐рдП:
- рдЗрд╕рдореЗрдВ рд╢рд╛рдпрдж рдЙрд╕ body рдХреА declaration рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдП рдЬрд┐рд╕реЗ рдЗрд╕реЗ receive рдХрд░рдирд╛ рд╣реИ, рдЬреИрд╕реЗ
body: InvoiceEventред - рдФрд░ рдЗрд╕рдореЗрдВ рдЙрд╕ response рдХреА declaration рднреА рд╣реЛ рд╕рдХрддреА рд╣реИ рдЬрд┐рд╕реЗ рдЗрд╕реЗ рд▓реМрдЯрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рдЬреИрд╕реЗ
response_model=InvoiceEventReceivedред
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}
рд╕рд╛рдорд╛рдиреНрдп path operation рд╕реЗ 2 рдореБрдЦреНрдп рдЕрдВрддрд░ рд╣реИрдВ:
- рдЗрд╕рдореЗрдВ рдХреЛрдИ рд╡рд╛рд╕реНрддрд╡рд┐рдХ code рд╣реЛрдирд╛ required рдирд╣реАрдВ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЖрдкрдХреА app рдЗрд╕ code рдХреЛ рдХрднреА call рдирд╣реАрдВ рдХрд░реЗрдЧреАред рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреЗрд╡рд▓ external API рдХреЛ document рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, function рдореЗрдВ рдХреЗрд╡рд▓
passрд╣реЛ рд╕рдХрддрд╛ рд╣реИред - path рдореЗрдВ рдПрдХ OpenAPI 3 expression (рдиреАрдЪреЗ рдФрд░ рджреЗрдЦреЗрдВ) рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдЬрд╣рд╛рдБ рдпрд╣ рдЖрдкрдХреА API рдХреЛ рднреЗрдЬреА рдЧрдИ original request рдХреЗ parameters рдФрд░ parts рдХреЗ рд╕рд╛рде variables рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддрд╛ рд╣реИред
Callback path expression
Callback path рдореЗрдВ рдПрдХ OpenAPI 3 expression рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдЬреЛ рдЖрдкрдХреА API рдХреЛ рднреЗрдЬреА рдЧрдИ original request рдХреЗ parts рд╢рд╛рдорд┐рд▓ рдХрд░ рд╕рдХрддрд╛ рд╣реИред
рдЗрд╕ case рдореЗрдВ, рдпрд╣ str рд╣реИ:
"{$callback_url}/invoices/{$request.body.id}"
рддреЛ, рдпрджрд┐ рдЖрдкрдХрд╛ API user (external developer) рдЖрдкрдХреА API рдХреЛ request рднреЗрдЬрддрд╛ рд╣реИ:
https://yourapi.com/invoices/?callback_url=https://www.external.org/events
рдЗрд╕ JSON body рдХреЗ рд╕рд╛рде:
{
"id": "2expen51ve",
"customer": "Mr. Richie Rich",
"total": "9999"
}
рддреЛ рдЖрдкрдХреА API invoice рдХреЛ process рдХрд░реЗрдЧреА, рдФрд░ рдмрд╛рдж рдореЗрдВ рдХрд┐рд╕реА рд╕рдордп, callback_url (external API) рдХреЛ callback request рднреЗрдЬреЗрдЧреА:
https://www.external.org/events/invoices/2expen51ve
рдРрд╕реЗ JSON body рдХреЗ рд╕рд╛рде рдЬрд┐рд╕рдореЗрдВ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рд╣реЛрдЧрд╛:
{
"description": "Payment celebration",
"paid": true
}
рдФрд░ рдпрд╣ рдЙрд╕ external API рд╕реЗ рдЗрд╕ рддрд░рд╣ рдХреЗ JSON body рд╡рд╛рд▓реЗ response рдХреА рдЕрдкреЗрдХреНрд╖рд╛ рдХрд░реЗрдЧреА:
{
"ok": true
}
/// tip | рд╕реБрдЭрд╛рд╡
рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЧрдП callback URL рдореЗрдВ callback_url (https://www.external.org/events) рдореЗрдВ query parameter рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рд╛рдкреНрдд URL рдФрд░ JSON body рдХреЗ рдЕрдВрджрд░ рд╕реЗ invoice id (2expen51ve) рджреЛрдиреЛрдВ рд╢рд╛рдорд┐рд▓ рд╣реИрдВред
///
Callback router рдЬреЛрдбрд╝реЗрдВ
рдЗрд╕ рд╕рдордп рдЖрдкрдХреЗ рдкрд╛рд╕ рдКрдкрд░ рдмрдирд╛рдП рдЧрдП callback router рдореЗрдВ required callback path operation(s) рд╣реИрдВ (рд╡реЗ operation рдЬрд┐рдиреНрд╣реЗрдВ external developer рдХреЛ external API рдореЗрдВ implement рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП)ред
рдЕрдм рдЖрдкрдХреА API рдХреЗ path operation decorator рдореЗрдВ parameter callbacks рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЙрд╕ callback router рд╕реЗ attribute .routes pass рдХрд░реЗрдВ:
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}
/// tip | рд╕реБрдЭрд╛рд╡
рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдЖрдк router рд╕реНрд╡рдпрдВ (invoices_callback_router) рдХреЛ callbacks= рдореЗрдВ pass рдирд╣реАрдВ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдмрд▓реНрдХрд┐ рдЙрд╕рдХреА .routes рдХреЛ pass рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдЬреИрд╕реЗ invoices_callback_router.routesред FastAPI рдЙрди routes рдХрд╛ рдЙрдкрдпреЛрдЧ callback OpenAPI documentation generate рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд░реЗрдЧрд╛ред
///
Docs рджреЗрдЦреЗрдВ
рдЕрдм рдЖрдк рдЕрдкрдиреА app start рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ http://127.0.0.1:8000/docs рдкрд░ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВред
рдЖрдкрдХреЛ рдЕрдкрдиреА docs рдореЗрдВ рдЕрдкрдиреЗ path operation рдХреЗ рд▓рд┐рдП рдПрдХ "Callbacks" section рджрд┐рдЦреЗрдЧрд╛, рдЬреЛ рджрд┐рдЦрд╛рддрд╛ рд╣реИ рдХрд┐ external API рдХреИрд╕реА рджрд┐рдЦрдиреА рдЪрд╛рд╣рд┐рдП: