There are several ways to notify other application/system that something has happened in your application, you can decide to schedule a cron job that hit the external system API endpoint at an internal but this might lead to making many unnecessary requests and reaching the API throttle limit.
You can also decide to hit the external application’s API endpoint whenever the event you want to notify the other system has happened in your application, but, what if the endpoint is down at that particular moment you are trying to hit it? — then you won’t be able to notify the system at that moment.
If you have tried or thought of taking the above approaches — then it’s time to try out webhook.
So, let’s get started by explaining what a webhook is and how to configure, and implement it in your laravel application?
What is a Webhook?
A webhook is a process whereby an application notifies another application that something has happened or an event has happened in the application. For techies, it’s a process whereby an application sends an HTTP request to another application whenever an event happens in an application.
So, to provide a suitable solution to your problem, I would like to introduce you to a laravel package that allows you to send webhook requests — Laravel-webhook-server.
This package allows you to configure and send webhooks easily. Below are some of the features of this package:
Signing calls:- This helps to verify that the request body hasn’t been tampered with by someone else. The signature will be added to the request’s header. You can also decide not to add signing to the request body if not needed. The package also allows you to customize your signer. Retrying calls:- If the external application API endpoint fails while your application was trying to hit it — this package will hit the endpoint again and again until it gets a response status of 2XX (200, 201, 202…2XX) Backoff strategies:- While retrying the calls, this package will release the job back into the queue with a delay, so it doesn’t keep hitting the external application’s API endpoint. So, the time for the attempts is determined by the backup strategy. Emit event:- If your application successfully notifies the other Application — this package fires an event — WebhookCallSucceededEvent and if it fails while making the call — it fires an event — WebhookCallFailedEvent. Lastly, if your application failed after several calls where the backoff strategy comes in — it fires an event — FinalWebhookCallFailedEvent Send webhook synchronously: This package uses queue as its default setting, so if you need to send a webhook synchronously, you can add dispatchSync instead of dispatch to the method. Customize HTTP verb: The external application API’s endpoint might used other HTTP verbs instead of POST, so, this package provides a way to use different HTTP verbs. Adding extra headers: With this feature, you can add headers to the request headers Adding meta information: This is useful if you need to pass extra information to the event listener You can check out the package repository on GitHub to read more of the amazing features this package offers.
How to Install and Configure Laravel Webhook Server In Laravel App.
Open your terminal and run composer require spatie/laravel-webhook-server To change some of the default configurations run: php artisan vendor:publish —provider=“Spatie\WebhookServer\WebhookServerServiceProvider” This will create a new file webhook-server.php in the config folder. Below is the content of the config/webhook-server.php
Implementing Laravel-webhook-server
In this section — I will use a simple laravel application to practicalize how to implement the laravel webhook server.
This application notifies an external system whenever a new user registers on the application, sends details of the user to the external system, and updates the webhook_status of the new user on the user’s table.
First, let’s create a user model and migration
php artisan make:model User -m This command will create a user model and the user migration.
Your user’s migration should look like this and don’t forget to run:
php artisan migrate
And your User’s model should be like this:
Next, let’s create the user’s form request
php artisan make:request UserRequest This will handle form validation and return errors if the validation fails
The app/Http/Requests/UserRequest.php should look like this:
Let’s generate an event and listener for user’s registration and also a listener for WebhookCallSucceededEvent and FinalWebhookCallFailedEvent event.
Open the app/providers/EventServiceProvider.php and update it to:
Then run:
php artisan event:generate This command will create a file named “NewUserEvent.php” in the app/Events folder and three files named “RegisterEventHandler.php”, “WebhookCallSucceededEventHandler.php”, and “FinalWebhookCallFailedEvent” in the app/Listeners folder.
You can then update the files to the content below respectively
PS: if you are using laravel < version 9 — it is advisable you add the below code before the _contructor method
public $user;
The RegisterEventHandler.php listens to the event fires by the NewUserEvent and gets the argument passed to the NewUserEvent event and dispatch the webhook call
PS:
The URL is the external application URL that will receive the webhook Don’t forget to import the Spatie\WebhookServer\WebhookCall Also, add the WEBHOOK_SECRET_KEY key with the value in the .env file. The receiving application will use this to verify the payload
The WebhookCallSucceededEventHandler listens to the WebhookCallSucceededEvent event (the laravel webhook-server package fires this when the receiving application returns status of 2XX) and updates the webhook_status column on the user’s table to true.
The FinalWebhookCallFailedEventHandler listens to the FinalWebhookCallFailedEvent event (the laravel webhook-server package fires this when the receiving application returns a status that is not in the range of 2XX) and logs the event in the log file.
PS:
I am just logging the event here for testing sake — You can use the payload in the event to perform another logic in your application. You need to update the configuration in webhook-server.php file in the config/webhook-server.php folder to throw an exception on failure for the listener to be able to listen to the FinalWebhookCallFailedEvent event effectively. ‘throw_exception_on_failure’ => true, Let’s set up the queue:
Go to your .env file and set the QUEUE_CONNECTION to the queue driver of your choice. I will be using database for this. QUEUE_CONNECTION=database The run: php artisan queue:table php artisan migrate The first command creates a migration forjobs table while the second command runs the migration
Also, to handle failed jobs, run: php artisan queue:failed-table This will create a migration for the failed_jobs table, so we will be able to retry them in case the webhook fails. Don’t forget to run migration.
Let’s create the user’s controller:
php artisan make:controller UserController
The UserController handles the logic — the create method returns the view for the form for registration while the store method saves the user’s detail after being validated by the UserRequest (form request handler) and fires the NewUserEvent event.
Let’s create the form for registration
Create a file name “register.php” in the “resources/views” folder and add the code below
Finally, let’s update the “routes/web.php” file 💃
Tadda 😃, we just implemented a webhook in our laravel application with the help of laravel-webhook-server package.
Take Note: Don’t forget to run:
php artisan queue:listen for the jobs to be processed.
And if by any chance the webhook fails, it will be pushed to the failed_jobs table, so you can run:
php artisan queue:retry all This command will push back the failed jobs in the queue — i.e. it will push the failed_jobs to the jobs table for processing
You can read more about Laravel queue here
You can clone the project from GitHub https://github.com/CodeAddictx10/laravel-webhook.git