Webhooks in Magento 2

hookThis post explores a short term approach for implementing a webhook in Magento 2. Better support for webhooks is on the backlog, but currently not guaranteed for Magento 2 GA.

So what is a webhook? Put simply, it is when software can be configured to send a HTTP request to a configurable destination (URL) when some event of interest occurs. For example, you might want a webhook called every time a new order is accepted from a customer – there may be an external system you want notified that the new order exists.

So why are webhooks hard to add to Magento? Magento has always had the concept of events, so has a logical place for webhooks to integrate with.

The first issue is more that you would really prefer webhook calls to be performed asynchronously so they do not slow down the main processing flow. You don’t want your PHP code to block because of a slow external URL. This post does not address this issue.

Another issue is events are frequently passed classes. To send data to a remote end point, the relevant data from the class needs to be serialized into some data structure like JSON or XML which is then POSTed to the configured URL. So some serialization code is required. It would be nice if that was configurable, but for this post good old PHP will be used.

So next I thought “great, I will go implement a sample module that implements a webhook by registering an observer that sends a HTTP request to a remote end point”. I thought this could be a useful example to create. Being a good software engineer, my first job was to find some good code to copy and adjust.

The file I picked was the Observer.php file in the Magento_CacheInvalidate module. It was an observer implementation that was fairly short, there was an events.xml file, there was a reference to curl, … hang on!

You guessed it, the Magento_CacheInvalidate module actually only contains one thing – an observer implementing a webhook notify an external URL when to flush its cache! So much for my grand plans to implement a new sample webhook module.

So how does it work?

  • First, there is an events.xml file in the etc directory binding various events to functions in the Observer class.
  • Next, if you look at the Observer constructor you will see a reference to \Magento\Framework\HTTP\Adapter\Curl. The dependency injection framework will provide this instance to your observer for talking to the PHP curl library (a HTTP client library built into PHP).
  • If you look invalidateVarnish() you will see example code that extracts information from the event to form the data to send to Varnish. It calls sendPurgeRequest() which puts the string into a HTTP header field. This could be easily adjusted to generate a JSON or XML payload instead.
  • The flushAllCache() function is even simpler. It shows an example of sending a webhook call where nothing is extracted from the event.

This particular example includes a bit of custom logic – there are configuration settings that are used to see if Varnish is enabled that is not required for a normal webhook. The invalidateVarnish() function also joins a few strings to form the correct Varnish header string.

So let’s see how short a webhook could be. I took the flushAllCache() function and stripped all comments and unneeded data structures. Obviously you should not do this in real life, but it helps show the complexity of the code required. I also removed the Varnish specific ‘if enabled’ check. Finally, I made the constructor get the URL from the di.xml file. As you can see, not much code is required to implement a web hook. You do need to add code to extract data from the event if you want to send that data to the end point, but it’s pretty easy to do with PHP with its built in JSON and XML support.

<?php
namespace Magento\CacheInvalidate\Model;

class Observer
{
    protected $url;
    protected $curlAdapter;

    /**
     * Constructor
     *
     * @param string $url
     * @param \Magento\Framework\HTTP\Adapter\Curl $curlAdapter
     */
    public function __construct(
        $url,
        \Magento\Framework\HTTP\Adapter\Curl $curlAdapter
    ) {
        $this->url = $url;
        $this->curlAdapter = $curlAdapter;
    }

    public function flushAllCache(\Magento\Framework\Event\Observer $observer)
    {
        $headers = ["X-Magento-Tags-Pattern: .*"];
        $this->curlAdapter->setOptions([CURLOPT_CUSTOMREQUEST => 'PURGE']);
        $this->curlAdapter->write('', $this->url, '1.1', $headers);
        $this->curlAdapter->read();
        $this->curlAdapter->close();
    }
}

So that is it! My sample webhook without actually needing to write one. A sample that is built in by default to every installation.

10 comments

  1. Hi Alan, greetings from Sydney. Are webhooks for Magento 2 still on the roadmap? I’m desperately looking forward to order/product created/updated/deleted events.
    Thanks

    1. You can implement your own web hooks based on events now. No webhooks in 2.2 which means 2.3 at earliest, which is some time off.

      1. Thanks Alan.
        I should have added, my app acts as a 3rd party and will connect to many stores (thus I need the webhooks). So I’m trying to do this via an extension or module. So far I have found one project looking into this @ https://github.com/smile-io/magento2-module-webhook
        Thanks

  2. can you explain how to install this module to magento.

    1. My code was just a sample fragment. I would hit the online magento docs if you need to understand how to build a module and install it. There is more than one approach.

  3. How to receive webhooks? Eg to put an order to completed?

    1. You would have to expose an API (REST endpoint) with suitable authentication to make sure the request can be trusted. This post is years old – I would check the latest docs for information on that.

      1. I was actually searching for docs on this, but everyone is discussing outgoing requests. I have the impression no one is addressing this. I think it is maybe not as trivial as it seems. I saw some post mentioning even the routing engine of magento. You have maybe a link?

      2. First question is if you are receiving a webhook, who defines the structure, how authentication is done, etc. If you have to obey someone else’s rules the default Magento 2 support might not work. Eg https://store.magenest.com/blog/how-to-create-custom-rest-api-in-magento-2-updated-2019/ I found at random, but it does not give complete control. I just queried for “Magento 2 custom rest api” and got lots of blogs etc.

      3. Cool, thanks, I was mostly searching receiving webhooks :/

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: