Callbacks na OpenAPI¶
🌐 Tradução por IA e humanos
Esta tradução foi feita por IA orientada por humanos. 🤝
Ela pode conter erros de interpretação do significado original ou soar pouco natural, etc. 🤖
Você pode melhorar esta traduçãoajudando-nos a orientar melhor o LLM de IA.
Você poderia criar uma API com umaoperação de rota que poderia acionar um request a umaAPI externa criada por outra pessoa (provavelmente o mesmo desenvolvedor que estariausando sua API).
O processo que acontece quando sua aplicação de API chama aAPI externa é chamado de "callback". Porque o software que o desenvolvedor externo escreveu envia um request para sua API e então sua APIchama de volta, enviando um request para umaAPI externa (que provavelmente foi criada pelo mesmo desenvolvedor).
Nesse caso, você poderia querer documentar como essa API externadeveria ser. Queoperação de rota ela deveria ter, que corpo ela deveria esperar, que resposta ela deveria retornar, etc.
Um aplicativo com callbacks¶
Vamos ver tudo isso com um exemplo.
Imagine que você desenvolve um aplicativo que permite criar faturas.
Essas faturas terão umid,title (opcional),customer etotal.
O usuário da sua API (um desenvolvedor externo) criará uma fatura na sua API com um request POST.
Então sua API irá (vamos imaginar):
- Enviar a fatura para algum cliente do desenvolvedor externo.
- Coletar o dinheiro.
- Enviar a notificação de volta para o usuário da API (o desenvolvedor externo).
- Isso será feito enviando um request POST (desua API) para algumaAPI externa fornecida por esse desenvolvedor externo (este é o "callback").
O aplicativoFastAPI normal¶
Vamos primeiro ver como o aplicativo da API normal se pareceria antes de adicionar o callback.
Ele terá umaoperação de rota que receberá um corpoInvoice, e um parâmetro de consultacallback_url que conterá a URL para o callback.
Essa parte é bastante normal, a maior parte do código provavelmente já é familiar para você:
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"}Dica
O parâmetro de consultacallback_url usa um tipo PydanticUrl.
A única novidade é ocallbacks=invoices_callback_router.routes como argumento do decorador daoperação de rota. Veremos o que é isso a seguir.
Documentando o callback¶
O código real do callback dependerá muito da sua própria aplicação de API.
E provavelmente variará muito de um aplicativo para o outro.
Poderia ser apenas uma ou duas linhas de código, como:
callback_url="https://example.com/api/v1/invoices/events/"httpx.post(callback_url,json={"description":"Invoice paid","paid":True})Mas possivelmente a parte mais importante do callback é garantir que o usuário da sua API (o desenvolvedor externo) implemente aAPI externa corretamente, de acordo com os dados quesua API vai enviar no corpo do request do callback, etc.
Então, o que faremos a seguir é adicionar o código para documentar como essaAPI externa deve ser para receber o callback desua API.
A documentação aparecerá na Swagger UI em/docs na sua API, e permitirá que os desenvolvedores externos saibam como construir aAPI externa.
Esse exemplo não implementa o callback em si (que poderia ser apenas uma linha de código), apenas a parte da documentação.
Dica
O callback real é apenas um request HTTP.
Ao implementar o callback por conta própria, você pode usar algo comoHTTPX ouRequests.
Escreva o código de documentação do callback¶
Esse código não será executado em seu aplicativo, nós só precisamos dele paradocumentar como essaAPI externa deveria ser.
Mas, você já sabe como criar facilmente documentação automática para uma API com oFastAPI.
Então vamos usar esse mesmo conhecimento para documentar como aAPI externa deveria ser... criando asoperações de rota que aAPI externa deveria implementar (as que sua API irá chamar).
Dica
Ao escrever o código para documentar um callback, pode ser útil imaginar que você é aqueledesenvolvedor externo. E que você está atualmente implementando aAPI externa, nãosua API.
Adotar temporariamente esse ponto de vista (dodesenvolvedor externo) pode ajudar a perceber mais facilmente onde colocar os parâmetros, o modelo Pydantic para o corpo, para a resposta, etc. para essaAPI externa.
Crie umAPIRouter de callback¶
Primeiro crie um novoAPIRouter que conterá um ou mais 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"}Crie aoperação de rota do callback¶
Para criar aoperação de rota do callback, use o mesmoAPIRouter que você criou acima.
Ela deve parecer exatamente como umaoperação de rota normal do FastAPI:
- Ela provavelmente deveria ter uma declaração do corpo que deveria receber, por exemplo,
body: InvoiceEvent. - E também poderia ter uma declaração da resposta que deveria retornar, por exemplo,
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"}Há 2 diferenças principais de umaoperação de rota normal:
- Ela não necessita ter nenhum código real, porque seu aplicativo nunca chamará esse código. Ele é usado apenas para documentar aAPI externa. Então, a função poderia ter apenas
pass. - Opath pode conter umaexpressão OpenAPI 3 (veja mais abaixo) em que pode usar variáveis com parâmetros e partes do request original enviado parasua API.
A expressão do path do callback¶
Opath do callback pode ter umaexpressão OpenAPI 3 que pode conter partes do request original enviado parasua API.
Nesse caso, é astr:
"{$callback_url}/invoices/{$request.body.id}"Então, se o usuário da sua API (o desenvolvedor externo) enviar um request parasua API para:
https://yourapi.com/invoices/?callback_url=https://www.external.org/eventscom um corpo JSON de:
{"id":"2expen51ve","customer":"Mr. Richie Rich","total":"9999"}entãosua API processará a fatura e, em algum momento posterior, enviará um request de callback para ocallback_url (aAPI externa):
https://www.external.org/events/invoices/2expen51vecom um corpo JSON contendo algo como:
{"description":"Payment celebration","paid":true}e esperaria uma resposta daquelaAPI externa com um corpo JSON como:
{"ok":true}Dica
Perceba como a URL de callback usada contém a URL recebida como um parâmetro de consulta emcallback_url (https://www.external.org/events) e também oid da fatura de dentro do corpo JSON (2expen51ve).
Adicione o roteador de callback¶
Nesse ponto você tem a(s)operação(ões) de rota de callback necessária(s) (a(s) que odesenvolvedor externo deveria implementar naAPI externa) no roteador de callback que você criou acima.
Agora use o parâmetrocallbacks no decorador daoperação de rota da sua API para passar o atributo.routes (que é na verdade apenas umalist de rotas/operações de path) do roteador 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"}Dica
Perceba que você não está passando o roteador em si (invoices_callback_router) paracallback=, mas o atributo.routes, como eminvoices_callback_router.routes.
Verifique a documentação¶
Agora você pode iniciar seu aplicativo e ir parahttp://127.0.0.1:8000/docs.
Você verá sua documentação incluindo uma seção "Callbacks" para suaoperação de rota que mostra como aAPI externa deveria ser:








