OpenAPI Webhooks are those cases where you want to tell your API users that your application could/should/would call their own application, for example, sending a request with specific bits of data, usually to notify them of some type of event.
This also means that instead of your users sending requests to your APIs, it is your application sendind requests to their application.
This process is called webhook.
Esmerald provides a way of declaring these webhooks in the OpenAPI specification. It is very, very similar to the way the Gateway is declared but dedicated to webhooks.
The process usually is that you define in your code, as normal, what is the message that you will send, in other words, the body of the request.
You also define in some way at which moments your app will send those requests or events.
Your users on the other hand, define some way (web dashboard, for instance) the URL where your application should send those requests.
The way the logic how to register the URLs for the webhooks and the code to performs the said actions is entirely up to you.
Documenting Esmerald webhooks with OpenAPI¶
As mentioned before, the way of doing it is very similar to the way you declare Gateway but for this purpose, webhooks have a special dedicated object or objects to do make it happen, the WebhookGateway.
Also, the webhooks are not hooked into the application routing system, instead, they are
placed in the
from esmerald import Esmerald app = Esmerald(webhooks=[...])
As the name indicated, the
WebhookGateway is the main object where you declare the hooks for
the OpenAPI specification and unlike the Gateway, it does not declare a
instead, it only needs to receive the name of the action.
Like the Gateway, the WebhookGateway also expects a handler but not the same handler as you usually use for the routes, a special webhook handler.
How to import it¶
You can import them directly:
from esmerald import WebhookGateway
Or you can use the full path.
from esmerald.routing.gateways import WebhookGateway
All the parameters and defaults are available in the WebhookGateway Reference.
The handlers for the webhooks are pretty much similar to the normal handlers used for routing but dedicated only to the WebhookGateway. The available handlers are:
- whget - For the
- whpost - For the
- whput - For the
- whpatch - For the
- whdelete - For the
- whead - For the
- whoptions - For the
- whtrace - For the
whroute - Used to specificy for which
http verbsis available. This handler has the special
from esmerald import whroute @whroute(methods=["GET", "POST"]) ...
As you can already see, the handlers are very similar to the routing handler but
dedicated to this purpose and all of them start with
wh at the beginning of each handler means WebHook.
How to import them¶
You can import them directly:
from esmerald import ( whdelete, whead, whget, whoptions, whpatch, whpost, whput, whroute, whtrace )
Or via full path.
from esmerald.routing.webhooks.handlers import ( whdelete, whead, whget, whoptions, whpatch, whpost, whput, whroute, whtrace )
An Esmerald application with webhooks¶
When you create an Esmerald application, as mentioned before, there is a
that you use to define your application
webhooks, in a similar way you define the
from datetime import datetime from pydantic import BaseModel from esmerald import Esmerald, Gateway, post from esmerald.routing.gateways import WebhookGateway from esmerald.routing.webhooks.handlers import whpost class Payment(BaseModel): is_paid: bool amount: float paid_at: datetime @whpost("new-event") async def new_event(data: Payment) -> None: ... @post("/create") async def create_payment(data: Payment) -> None: ... app = Esmerald( routes=[Gateway(handler=create_payment)], webhooks=[WebhookGateway(handler=new_event)], )
Note how the
post are declared inside the
similar but not the same and how the
whpost does not require the
/ for the path.
The webhooks you define will end up in the OpenAPI schema automatically.
Using the APIView to generate webhooks¶
Since Esmerald supports class based views, that also means you can also use them to generate webhooks.
from datetime import datetime from pydantic import BaseModel from esmerald import APIView, Esmerald, Gateway, post from esmerald.routing.gateways import WebhookGateway from esmerald.routing.webhooks.handlers import whpost class Payment(BaseModel): is_paid: bool amount: float paid_at: datetime class PaymentWebhook(APIView): @whpost("new-event") async def new_event(self, data: Payment) -> None: ... @whpost("payments") async def new_payment(self, data: Payment) -> None: ... @post("/create") async def create_payment(data: Payment) -> None: ... app = Esmerald( routes=[Gateway(handler=create_payment)], webhooks=[WebhookGateway(handler=PaymentWebhook)], )
Notice that with webhooks you are actually not declaring a path (like
/user). The text you pass
there is just a
name or an identifier of the webhook (name of the event).
This happens because it is expected that your users would actually define the proper URL path where they want to receive the webhook in some way.
Check out the docs¶
Let us see how it would look like in the docs if we were declaring the webhooks from the examples.
First example, no Class Based Views
Second example, with Class Based Views