-
Notifications
You must be signed in to change notification settings - Fork 4
Tutorial: Creating Webhooks
One of the most common use cases of async events is to publish webhooks to external systems. In this tutorial we'll explore creating a simple webhook that is published to all subscribers when a sales order is placed.
Firstly, we'll need to define an asynchronous event so we can dispatch it. A definition of an asynchronous event describes the name of the event and the shape of the data that will be provided when the event is dispatched.
An advantage of this is that lot of the core Magento data interfaces that are used for web APIs can be reused. Which means, if those APIs ever get updated, you don't have to change a thing.
In your module's etc directory, create a new async_events.xml
file.
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Aligent_AsyncEvents:etc/async_events.xsd">
<async_event name="sales.order.created">
<service class="Magento\Sales\Api\OrderRepositoryInterface" method="get"/>
</async_event>
</config>
The above code defines a sales.order.created
. This asynchronous event will have some data that corresponds to the same interface as the orders API.
How do we know?
If you open Magento/Sales/etc/webapi.xml
and find the web API definition for Get /V1/orders/:id
we can see it's being powered by the same method of the same repository.
<route url="/V1/orders/:id" method="GET">
<service class="Magento\Sales\Api\OrderRepositoryInterface" method="get"/>
<!-- ... -->
</route>
Which means, you can pretty much turn any existing web API into a webhook. There are some caveats depending on the repositories, please see the warnings.
Once you have an asynchronous event defined, the next step is to create a subscription. Here we will use an HTTPs subscription. The REST API can be used to create a new subscription
curl --location --request POST 'https://magento.url/rest/V1/async_event' \
--header 'Authorization: Bearer TOKEN' \
--header 'Content-Type: application/json' \
--data-raw '{
"asyncEvent": {
"event_name": "sales.order.created",
"recipient_url": "https://example.com/order_handler"
"verification_token": "supersecret",
"metadata": "http"
}
}'
In the above example, we're creating a subscription for sales.order.created
which is the one we just defined in the previous step. We want that to be delivered to https://example.com/order_handler
. We also provide a secret (this is useful to sign payloads). Finally it specifies to use the http
notifier.
With an asynchronous event and one subscription setup, the only thing left is to dispatch it. This is just simply publishing to the event queue.
We want to dispatch this event after an order is placed. Therefore we will leverage the built-in sales_order_save_commit_after
event. Create a new event observer for this event. You could also use a plugin if you wanted to trigger this in a different place.
Then, inside our event handler we'll dispatch our asynchronous event with the required arguments to resolve that data.
public function execute(Observer $observer): void
{
/** @var Order $object */
$object = $observer->getEvent()->getData('order');
$this->publisher->publish(QueueMetadataInterface::EVENT_QUEUE, [
'sales.order.created',
$this->json->serialize([
'id' => $object->getId()
])
]);
}
This just simply delegates it to the async events. Note that we dispatch sales.order.created
and we provide the id
argument. Note that you are not publishing the entire payload into the queue! (This might be useful in cases where your payload is just too big to fit into a queue message) Just enough information that is required by the service method you defined in async_events.xml
.
If your queue consumers are running, then as soon as an order is placed, it will be sent to all subscribers in real time.
i.e:
bin/magento queue:consumer:start event.trigger.consumer