Laravel Reverb - Bidirectional Communication
Tags: laravel, php
Published: 2024-03-31 15:07:57

Hello fellow artisans! Today, I'm excited to share with you how to use Laravel Reverb as a WebSocket server for two-way communication between the server and the client.

In many tutorials and blogs I've come across, they only cover server-to-client communication. For instance, in a real-time chat app, the client sends a message to the server through an API request, and then the server distributes it to other clients. But this approach isn't ideal because it involves numerous API calls for each message, which can become inefficient as the volume of messages grows.

## What is Reverb?

Reverb is a first-party WebSocket server for Laravel applications, bringing real-time communication between client and server directly to your fingertips. Open source and an Artisan command away. 
[Check Documentation](https://laravel.com/docs/11.x/reverb)

## Setup Reverb

If you are using Laravel 11, first you will need to install Broadcasting:

```bash
php artisan install:broadcasting
```
This command will set Reverb as your default broadcaster. 

If you are still on Laravel 10, you will need some additional steps to setup Reverb:

```bash
composer require laravel/reverb:@beta 

php artisan reverb:install
```
Next, you need to enable broadcasting:

In your `config/app.php` uncomment the `BrodacastServiceProvider`

```php
 'providers' => ServiceProvider::defaultProviders()->merge([
        /*
         * Package Service Providers...
         */

        /*
         * Application Service Providers...
         */
        App\Providers\AppServiceProvider::class,
        App\Providers\AuthServiceProvider::class,
        App\Providers\BroadcastServiceProvider::class,
        App\Providers\EventServiceProvider::class,
        App\Providers\RouteServiceProvider::class, 
    ])->toArray(),

```

## How to send message from the client to the server 

First register an event that will broadcast the message:

```php
<?php

namespace App\Events;

use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;

class SendMessage implements ShouldBroadcastNow
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public readonly array $data; // this will depend based on your logic

    /**
     * Create a new event instance.
     */
    public function __construct(array $data)
    {
        $this->data = $data;
     
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return array<int, \Illuminate\Broadcasting\Channel>
     */
    public function broadcastOn(): PrivateChannel|array
    {
        return new PrivateChannel('channel.name');

    }
}


```

Laravel Reverb uses own event called `MessageReceived` which receives an event directly in Laravel application. To listen received events you need to register own listener.

For e.g.

```php
<?php

namespace App\Listeners;

use App\Events\SendMessage;
use Laravel\Reverb\Events\MessageReceived;

class BroadcastMessage
{
    /**
     * Create the event listener.
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     */
    public function handle(MessageReceived $event): void
    {
        $message = json_decode($event->message);

        $data = $message->data;

        if ($message->event === 'SendMessage') {
             
            // your logic goes here...

            $data = json_decode($data);

            $data = $data->messageData;

            broadcast(new SendMessage($data))->toOthers();

        }

    }
}
```

Do not forget to register your listener:

- Laravel 10

In your `EventServiceProvider`:

```php
<?php

namespace App\Providers;

use App\Listeners\BroadcastMessage;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
use Laravel\Reverb\Events\MessageReceived;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event to listener mappings for the application.
     *
     * @var array<class-string, array<int, class-string>>
     */
    protected $listen = [
      
    ];

    /**
     * Register any events for your application.
     */
    public function boot(): void
    {
        Event::listen(
            MessageReceived::class,
            BroadcastMessage::class
        );
    }

    /**
     * Determine if events and listeners should be automatically discovered.
     */
    public function shouldDiscoverEvents(): bool
    {
        return false;
    }
}


```

- In Laravel 11:

In your `AppServiceProvider` class:

```php
use App\Listeners\BroadcastMessage;
use Laravel\Reverb\Events\MessageReceived;
use Illuminate\Support\Facades\Event;
 
/**
 * Bootstrap any application services.
 */
public function boot(): void
{
     Event::listen(
            MessageReceived::class,
            BroadcastMessage::class
        );
}

```
For more detail check the [Documentation](https://laravel.com/docs/11.x/events#manually-registering-events)

## Send from Client to Server

Finally how can we send a message to the server. In my example I am using `Laravel Echo` package which uses Pusher protocols.

```js
Echo.connector.pusher.send_event('SendMessage',
                JSON.stringify({ messageData }), 'channel.name');

```

Note that this is just a quick start on how you can set up bidirectional communication for your Laravel application. Based on your logic and your needs you will need to check the official Laravel documentation. 

### Resources:
[https://laravel.com/docs/11.x/reverb](Reverb)
[https://laravel.com/docs/11.x/broadcasting](Broadcasting)
[https://laravel.com/docs/11.x/broadcasting#broadcasting-events](Listening Events)
[Joe Dixon - LaraconEU Talk ](https://www.youtube.com/watch?v=yrL5eCMpqtc&t=1761s&ab_channel=LaraconEU)