DEV Community

Nasrul Hazim Bin Mohamad
Nasrul Hazim Bin Mohamad

Posted on • Edited on

Webhook - Part III

Now we have the basic understanding of webhook as in my Webhook: Part I and we also creating our own first Webhook Provider as in Webhook: Part II.

Creating Webhook Consumer Application

First, make sure to create database for the application, I named it as webhook_client.

Then create the project, install the package and setup queue database:



laravel new webhook-client --git --jet --stack=livewire 
composer require spatie/laravel-webhook-client
php artisan vendor:publish --provider="Spatie\WebhookClient\WebhookClientServiceProvider" --tag="webhook-client-config"
php artisan vendor:publish --provider="Spatie\WebhookClient\WebhookClientServiceProvider" --tag="webhook-client-migrations"
php artisan queue:table
php artisan migrate


Enter fullscreen mode Exit fullscreen mode

Update the .env so that we are using database queue.



QUEUE_CONNECTION=database


Enter fullscreen mode Exit fullscreen mode

The Webhook Endpoint

The Laravel Webhook Client give you an easy way to setup the route, you simply add the following in your routes/web.php:



Route::webhooks('webhook/handler');


Enter fullscreen mode Exit fullscreen mode

And don't forget to disable the Verify CSRF Token as previous section.

Handling the Payload

Let's inspect what the Spatie Laravel Webhook Client provide in the configuration.



<?php

return [
    'configs' => [
        [
            'name' => 'default',
            'signing_secret' => env('WEBHOOK_CLIENT_SECRET'),
            'signature_header_name' => 'Signature',
            'signature_validator' => \Spatie\WebhookClient\SignatureValidator\DefaultSignatureValidator::class,
            'webhook_profile' => \Spatie\WebhookClient\WebhookProfile\ProcessEverythingWebhookProfile::class,
            'webhook_response' => \Spatie\WebhookClient\WebhookResponse\DefaultRespondsTo::class,
            'webhook_model' => \Spatie\WebhookClient\Models\WebhookCall::class,
            'store_headers' => [],
            'process_webhook_job' => '',
        ],
    ],
];


Enter fullscreen mode Exit fullscreen mode

Above are the default config and by default, the webhook handler will require the WEBHOOK_CLIENT_SECRET which will be use for signing the incoming payload.

You can have your own secret key, my favourite always generate it randomly - which achievable via tinker:



php artisan tinker
Psy Shell v0.11.7 (PHP 8.1.3 — cli) by Justin Hileman
>>> str()->random(32)
=> "8pZAOAyXfYKd3aAqdxYHsJf4oSTWafaG"


Enter fullscreen mode Exit fullscreen mode

Copy the generate key and save it .env file:



WEBHOOK_CLIENT_SECRET=8pZAOAyXfYKd3aAqdxYHsJf4oSTWafaG


Enter fullscreen mode Exit fullscreen mode

Then we need a Queue Job class for handling incoming payload:



php artisan make:job WebhookHandler


Enter fullscreen mode Exit fullscreen mode

Open up the app/Jobs/WebhookHandler.php and update it's extend class as following:



<?php

namespace App\Jobs;

class WebhookHandler extends \Spatie\WebhookClient\Jobs\ProcessWebhookJob
{
    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        // do your things here with $this->webhookCall
        logger()->info($this->webhookCall->payload);
    }
}


Enter fullscreen mode Exit fullscreen mode

And update the config/webhook-client.php:



'process_webhook_job' => \App\Jobs\WebhookHandler::class,


Enter fullscreen mode Exit fullscreen mode

Update Webhook Provider

And remember in Webhook Provider, we have the useSecret() method when sending the payload? Yes, you need this secret key to be share in the Webhook Provider, else you will never get to process the payload if the signature is invalid.

Let's do quick update on Webhook Provider:

On app/Models/User.php, noted on url() and useSecret() using the config() helper, calling our custom webhook config.



static::created(function(User $model) {
    WebhookCall::create()
        ->url(config('webhook.user.url'))
        ->payload($model->toArray())
        ->throwExceptionOnFailure()
        ->useSecret(config('webhook.user.secret'))
        ->dispatch();
});


Enter fullscreen mode Exit fullscreen mode

In the Webhook Provider, add a new configuration file config/webhook.php:



<?php 

return [
    'user' => [
        'name' => 'Webhook Consumer: User',
        'url' => env('WEBHOOK_CONSUMER_URL'),
        'secret' => env('WEBHOOK_CONSUMER_SECRET')
    ],
];


Enter fullscreen mode Exit fullscreen mode

Then in .env:



WEBHOOK_CONSUMER_URL=http://127.0.0.1:8001/webhook/handler
WEBHOOK_CONSUMER_SECRET=8pZAOAyXfYKd3aAqdxYHsJf4oSTWafaG


Enter fullscreen mode Exit fullscreen mode

Note the Webhook Consumer URL, I just run using php artisan serve for quick setup and testing.

Testing the Webhook

Now we are ready to test our Webhook Provider & Webhook Consumer.

Let's run the application and queue:



php artisan serve
php artisan queue:work


Enter fullscreen mode Exit fullscreen mode

Run in both Webhook Provider and Consumer.

Then go ahead register new account in http://localhost:8000.

Now inspect in your Webhook Consumer log file, you should get something like the following:



[2022-07-12 04:07:52] local.INFO: array (
  'id' => 2,
  'name' => 'Malik Rich',
  'email' => 'zomunudut@mailinator.com',
  'created_at' => '2022-07-12T04:07:48.000000Z',
  'updated_at' => '2022-07-12T04:07:48.000000Z',
  'profile_photo_url' => 'https://ui-avatars.com/api/?name=M+R&color=7F9CF5&background=EBF4FF',
)  


Enter fullscreen mode Exit fullscreen mode

If you get this right, then you on the right path. If not, you may want to look into the queue & route. Make sure it's properly configured.

Image description

Top comments (0)