Membuat Webhook Menggunakan Notifikasi DI Laravel - CRUDPRO

Membuat Webhook Menggunakan Notifikasi DI Laravel

Membuat Webhook Menggunakan Notifikasi DI Laravel

Kami sering kali harus menerapkan webhook saat mengintegrasikan layanan pihak ketiga. Webhook adalah tempat satu aplikasi web mengirimkan data atau peristiwa ke aplikasi web lain melalui permintaan HTTP. Misalnya sebagian besar layanan email seperti mailgun dan spark post akan mengirim pesan yang terkait dengan hard bounce atau pemberitahuan spam saat mereka mengirimkan email aplikasi Anda.

Sangat mudah untuk menerima pesan webhook hanya dengan membuat pengontrol dan hampir semudah mengirimnya melalui kerangka notifikasi luar biasa Laravel. Cara kami melakukannya adalah dengan membuat saluran notifikasi khusus.

Memasang Dependensi Kami

Pertama kita perlu menginstal perpustakaan untuk mengirim permintaan HTTP. Yang akan kita gunakan di sini adalah Guzzle yang cukup umum digunakan oleh sebagian besar aplikasi web PHP dalam satu atau lain cara.

Kita dapat menginstal ini dengan menggunakan composer.

composer require guzzlehttp/guzzle:~6.0

Setelah melakukannya, kami dapat mulai membuat saluran Pemberitahuan Webhook baru kami.

Saluran Pemberitahuan

Saluran notifikasi di Laravel menetapkan mekanisme pengiriman pesan terstruktur ke pengguna, tim, apa pun yang Anda anggap cocok melalui banyak "saluran" yang bisa berupa email, saluran slack, atau Pesan SMS. Saluran itu sendiri sering mengirim permintaan HTTP jadi ini bukan sesuatu yang benar-benar baru yang kami lakukan di sini.

Pertama kita akan membuat folder app/Channels dan di dalamnya kita akan membuat kelas WebhookChannel. Kelas ini akan mengimplementasikan metode send yang mengambil objek Notifiable dan objek Notification.

Karena bagaimana saluran digunakan oleh kerangka kerja, kami juga akan menempatkan beberapa dependensi di kelas baru kami dengan memiliki konstruktor yang mengambil klien Guzzle dan instance logger ke saluran kami. Logger terutama ada untuk membuat hidup kita sedikit lebih mudah untuk memastikan pesan kita terkirim.

Jadi pada titik ini WebhookChannel kita akan terlihat seperti ini:

<?php

namespace App\Channels;

use GuzzleHttp\Client;
use Illuminate\Log\Logger;
use Illuminate\Notifications\Notifiable;
use Illuminate\Notifications\Notification;

class WebhookChannel
{
    /**
     * @var Client
     */
    private $client;
    /**
     * @var Logger
     */
    private $logger;

    public function __construct(Client $client, Logger $logger)
    {
        $this->client = $client;
        $this->logger = $logger;
    }

    /**
     * @param Notifiable $notifiable
     * @param Notification $notification
     * @throws WebHookFailedException
     */
    public function send($notifiable, Notification $notification)
    {

    }
}

Kami akan menerapkan metode yang sebenarnya nanti, tetapi untuk saat ini kami akan membuat ciri kami sendiri yang dapat diberitahukan untuk membakukan bagaimana dan apa yang dapat menerima pemberitahuan melalui webhook.

Ciri khas Webhook

Pada titik ini seperti sifat yang Dapat Diberitahukan, kita akan membuat sifat untuk objek yang dapat diberi tahu oleh webhook. Ini sebenarnya tidak perlu, tetapi ini adalah cara yang bagus untuk menetapkan metode yang mudah ditambahkan ke kelas apa pun yang kita inginkan.

Kami sekarang akan membuat sifat baru yang disebut WebhookNotifiable di folder aplikasi yang memiliki dua metode, getSigningKey() dan getWebhookUrl(). Kedua metode ini akan diperlukan sebagai bagian dari proses webhook baru kami. Metode hanya akan mengakses properti objek menggunakan ciri-ciri, dalam hal ini properti webhook_url dan api_key, yang pertama menjadi tujuan pemberitahuan dan yang terakhir api_key akan digunakan untuk memberi pengguna akhir cara memverifikasi permintaan HTTP apa pun bahwa kami mengirim mereka.

<pre style="background-color: transparent; border: medium none;"><code class="php"><?php

namespace App;

trait WebhookNotifiable
{
    /**
     * @return string
     */
    public function getSigningKey()
    {
        return $this->api_key;
    }

    /**
     * @return string
     */
    public function getWebhookUrl()
    {
        return $this->webhook_url;
    }
}</code></pre>
Membuat pengguna yang dapat menerima notifikasi Webhook

Langkah selanjutnya adalah membuat pengguna kami bekerja dengan sifat tersebut. Ini hanya akan memakan waktu satu detik dengan memodifikasi tabel migrasi pengguna dan membuat bidang untuk menyimpan api_key dan webhook_url. Sementara pada saat yang sama kami akan menambahkan sifat ke kelas Pengguna yang ditemukan di app/User.php. Bukan bagaimana pengguna sudah menggunakan sifat yang Dapat Diberitahukan dan kami hanya menambahkan yang tambahan ini.

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable, WebhookNotifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password', 'api_key', 'webhook_url',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token', 'api_key',
    ];
}
Menyelesaikan Saluran Webhook kami

Sekarang kami memiliki sifat yang dapat diberitahukan webhook, kami dapat menulis metode kirim untuk mengirimkan pemberitahuan kami melalui WebhookChannel kami. Kami akan mengedit metode kirim, pertama-tama memeriksa apakah notifikasi memiliki metode toWebHook() dan jika tidak maka itu akan memanggil toArray() sebagai gantinya. Laravel membuat notifikasi dengan toArray() secara default, tetapi ada baiknya memiliki opsi karena beberapa saluran mungkin menggunakan metode ini. Ini memungkinkan kami untuk mendapatkan konten dari notifikasi untuk dikirim ke Pengguna kami yang dapat diberitahu. Ini akan menjadi badan HTTP untuk permintaan webhook kami.

Kami kemudian akan membuat beberapa header untuk permintaan webhook. Kami melakukan ini agar pengguna yang menerimanya dapat memverifikasi bahwa notifikasi tersebut berasal dari kami dan bukan dari orang lain. Kami melakukan ini dengan melakukan hashing string acak dan cap waktu menggunakan kunci penandatanganan Pengguna. Memberikan stempel waktu adalah cara yang baik untuk memastikan permintaan dari hook tidak basi.

Setelah itu kita akan menggunakan klien Guzzle untuk mengirim pesan notifikasi kita. Jika kami tidak mendapatkan kode status HTTP 200, kami akan memberikan pengecualian. Dalam hal ini saya membuat WebhookFailedException sederhana hanya untuk membakukan proses. Kami juga memastikan bahwa jika Guzzle melempar pengecualian apa pun, kami menangkapnya dan melemparkannya kembali sebagai WebhookFailedException. Kami menggunakan pengecualian karena jika pemberitahuan diantrekan dan dikirim dalam proses latar belakang, pengecualian akan menyebabkan pemberitahuan diantrekan ulang untuk upaya lebih lanjut. Perhatikan bahwa kami juga menggunakan logger hanya untuk memperjelas bahwa permintaan berhasil atau gagal dengan menuliskannya ke file log.

<?php

namespace App\Channels;

use App\Exceptions\WebHookFailedException;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Psr7\Request;
use Illuminate\Log\Logger;
use Illuminate\Notifications\Notifiable;
use Illuminate\Notifications\Notification;

class WebhookChannel
{
    /**
     * @var Client
     */
    private $client;
    /**
     * @var Logger
     */
    private $logger;

    public function __construct(Client $client, Logger $logger)
    {
        $this->client = $client;
        $this->logger = $logger;
    }

    /**
     * @param Notifiable $notifiable
     * @param Notification $notification
     * @throws WebHookFailedException
     */
    public function send($notifiable, Notification $notification)
    {
        if (method_exists($notification, 'toWebhook')) {
            $body = (array) $notification->toWebhook($notifiable);
        } else {
            $body = $notification->toArray($notifiable);
        }
        $timestamp = now()->timestamp;
        $token = str_random(16);

        $headers = [
            'timestamp' => $timestamp,
            'token' => $token,
            'signature' => hash_hmac(
                'sha256',
                $token . $timestamp,
                $notifiable->getSigningKey()
            ),
        ];

        $request = new Request('POST', $notifiable->getWebhookUrl(), $headers, json_encode($body));

        try {
            $response = $this->client->send($request);

            if ($response->getStatusCode() !== 200) {
                throw new WebHookFailedException('Webhook received a non 200 response');
            }

            $this->logger->debug('Webhook successfully posted to '. $notifiable->getWebhookUrl());

            return;

        } catch (ClientException $exception) {
            if ($exception->getResponse()->getStatusCode() !== 410) {
                throw new WebHookFailedException($exception->getMessage(), $exception->getCode(), $exception);
            }
        } catch (GuzzleException $exception) {
            throw new WebHookFailedException($exception->getMessage(), $exception->getCode(), $exception);
        }

        $this->logger->error('Webhook failed in posting to '. $notifiable->getWebhookUrl());
    }
}
Contoh pemberitahuan

Sekarang setelah kita melalui proses pengaturan mekanisme untuk mengirim data melalui webhook, kita akan membuat contoh pemberitahuan cepat.

Ini dapat dilakukan dengan menggunakan perintah artisan php artisan make:notification SomethingHappenedNotification yang membuat kelas di file app/Notifications/SomethingHappenedNotification.php.

Kami akan memberikan notifikasi argumen $message, ini hanya sebagai contoh, untuk menunjukkan jenis data yang mungkin diteruskan ke notifikasi.

Kami dapat menghapus metode toMail() karena kami tidak akan menggunakan ini. Sebagai gantinya kami akan menambahkan metode toWebhook($notification) yang akan mengembalikan sebuah array. Dalam hal ini kami hanya akan menempatkan beberapa nilai demi mengujinya.

Untuk menyelesaikan semuanya, ubah metode via() mengembalikan array yang berisi kelas WebhookChannel. Ini akan memberi tahu Laravel bahwa notifikasi ini perlu dikirimkan melalui WebhookChannel. Kami juga menambahkan bahwa notifikasi harus diantrekan menggunakan antarmuka ShouldQueue. Ini sangat berguna karena artinya dapat ditangani pada antrian sehingga Laravel akan menanganinya sebagai proses latar belakang jika Anda mengimplementasikan antrian. Ini dapat berguna karena permintaan HTTP mungkin kehabisan waktu atau menahan respons apa pun yang Anda kirim ke pengguna Anda.

<?php

namespace App\Notifications;

use App\Channels\WebhookChannel;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;

class SomethingHappenedNotification extends Notification implements ShouldQueue
{
    use Queueable;
    /**
     * @var string
     */
    private $message;

    /**
     * Create a new notification instance.
     *
     * @param string $message
     */
    public function __construct($message)
    {
        //
        $this->message = $message;
    }

    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
        return [WebhookChannel::class];
    }

    public function toWebhook($notifiable)
    {
        return [
            'message' => $this->message,
        ];
    }

    /**
     * Get the array representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function toArray($notifiable)
    {
        return [];
    }
}
Menguji semuanya

Jelas ini semua bisa sedikit sulit untuk beralih dari penerapan ke contoh kerja, jadi saya telah membangun proyek kecil saya sendiri yang tersedia di GitHub yang dapat Anda mainkan. Ada beberapa petunjuk dasar dalam readme yang dapat Anda ikuti untuk memulainya.

Membuat Webhook Menggunakan Notifikasi DI Laravel
kesimpulan

Yah tidak banyak yang tersisa untuk dikatakan. Notifikasi di Laravel telah ada sejak versi 5.3 dan ini adalah salah satu fitur unik yang sangat membantu framework menonjol. Apa yang hebat tentang itu adalah bahwa itu sangat dapat diperpanjang dan dapat digunakan untuk menyederhanakan proses yang membutuhkan pesan yang dikirim ke penerima individu. Apa yang lebih baik lagi adalah memungkinkan antrian pesan yang mungkin tampak tidak penting ketika Anda memulai, tetapi ini benar-benar dapat membantu mempercepat permintaan aplikasi Anda seiring bertambahnya basis pengguna Anda. Secara keseluruhan, jika Anda belum membaca notifikasi di Laravel sekarang, saya sangat menyarankan Anda melakukannya.