Laravel API Broadcast Driver: Custom Laravel Driver for Sending Event to API endpoint.

Emeka Mbah
5 min readMay 21, 2024

--

Laravel’s event broadcasting is a powerful feature that provides a seamless method for “broadcasting” your server-side Laravel events via a WebSocket connection. This allows you to share the same event names and data between your client-side JavaScript and server-side Laravel applications, enhancing the efficiency and effectiveness of your development process.

By default, Laravel includes three server-side broadcasting drivers: Laravel Reverb, Pusher Channels, and Ably. These drivers broadcast events server-side via WebSockets to the client side. However, what if you want to broadcast events fluently from server to server? None of the broadcasting drivers currently support this.

This tutorial will create a custom broadcasting driver for broadcasting events over an API endpoint.

To create your custom broadcasting driver, you must extend the Laravel broadcasting system and define the necessary methods to integrate with your custom service.

Here’s a step-by-step guide on how to create a custom broadcasting driver in Laravel:

Step 1: Create the Custom Broadcasting Driver Class

First, create a new class serving as your custom broadcasting driver. This class should implement the Illuminate\Contracts\Broadcasting\Broadcaster interface and extend the Illuminate\Broadcasting\Broadcasters\Broadcaster class.

<?php

namespace App\Broadcasting;

use Exception;
use Illuminate\Broadcasting\Broadcasters\Broadcaster;
use Illuminate\Contracts\Broadcasting\Broadcaster as BroadcasterContract;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;

class HttpBroadcaster extends Broadcaster implements BroadcasterContract
{
/**
* The base URL of the broadcasting service.
*
* @var string
*/
private string $baseUrl;

/**
* The token used to authenticate with the broadcasting service.
*
* @var string
*/
private string $token;

/**
* The key used to authenticate with the broadcasting service.
*
* @var string
*/
private string $key;

/**
* The type of authentication used to authenticate with the broadcasting service.
*
* @var string
*/
private string $authType;

/**
* The endpoint to which the broadcast will be sent.
*
* @var string
*/
private string $endpoint;

/**
* The headers to be sent with the broadcast.
*
* @var array
*/
private array $headers = [];

/**
* Whether to verify the SSL certificate of the broadcasting service.
*
* @var bool
*/
private bool $verify = true;

public function __construct(
private array $config = []
) {
// set defaults
$this->setBaseUrl($this->config['base_url'] ?? '');
$this->setToken($this->config['token'] ?? '');
$this->setKey($this->config['key'] ?? '');
$this->setAuthType($this->config['auth'] ?? 'bearer');
$this->setVerify($this->config['verify'] ?? true);
}

public function setBaseUrl(string $url): self
{
$this->baseUrl = rtrim($url, '/');
return $this;
}

public function setToken(string $token): self
{
$this->token = $token;
return $this;
}

public function setKey(string $key): self
{
$this->key = $key;
return $this;
}

public function setAuthType(string $authType): self
{
$this->authType = $authType;
return $this;
}

public function setEndpoint(string $endpoint): self
{
$this->endpoint = ltrim($endpoint, '/');
return $this;
}

public function setHeaders(array $headers): self
{
$this->headers = $headers;
return $this;
}

public function setVerify(bool $verify): self
{
$this->verify = $verify;
return $this;
}

public function client(): PendingRequest
{
if ($this->authType === 'null') {
return Http::withoutVerifying();
}

if ($this->authType === 'basic') {
return Http::withBasicAuth($this->key, $this->token);
}

if ($this->authType === 'digest') {
return Http::withDigestAuth($this->key, $this->token);
}

if ($this->authType === 'key') {
return Http::withHeaders([
'X-Api-Key' => $this->key,
]);
}

return Http::withToken($this->token);
}

/**
* @throws Exception
*/
public function auth($request)
{

}

/**
* @throws Exception
*/
public function validAuthenticationResponse($request, $result)
{

}

/**
* @throws Exception
*/
public function broadcast(array $channels, $event, array $payload = []): void
{
// Convert channels to the format required by your custom broadcaster
$formattedChannels = $this->formatChannels($channels);

// Send the payload to your custom broadcasting service
$response = $this->send($formattedChannels, $event, $payload);

if ($response->failed()) {
throw new Exception($response->reason());
}
}

protected function formatChannels(array $channels): array
{
return array_map(function ($channel) {
return str_replace('private-', '', $channel);
}, $channels);
}

protected function send(array $channels, string $event, array $payload): Response
{
$url = empty($this->endpoint)
? $this->baseUrl . '/' . $event
: $this->baseUrl . '/' . $this->endpoint;

$data = [
'channels' => $channels,
'event' => $event,
'payload' => $payload,
];

$request = $this->client();

if ($this->headers) {
$request->withHeaders($this->headers);
}

if (! $this->verify) {
$request->withoutVerifying();
}

return $request->post($url, $data);
}
}

Step 2: Register the Custom Broadcasting Driver

Next, you need to register your custom broadcasting driver with Laravel. You can do this in a service provider, typically in AppServiceProvider or a custom provider.

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\ServiceProvider;
use App\Broadcasting\HttpBroadcaster;

class BroadcastServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Broadcast::extend('http', function ($app, array $config) {
return new HttpBroadcaster($config);
});
}
}

Step 3: Update the Broadcasting Configuration

Now, update the config/broadcasting.php configuration file to include your custom driver. Add a new entry for your custom broadcaster under the connections array.

<?php

return [
'connections' => [

'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY', 'app-key'),
'secret' => env('PUSHER_APP_SECRET', 'app-secret'),
'app_id' => env('PUSHER_APP_ID', 'app-id'),
'options' => [
'host' => env('PUSHER_HOST', '127.0.0.1'),
'port' => env('PUSHER_PORT', 6001),
'scheme' => env('PUSHER_SCHEME', 'http'),
'encrypted' => env('PUSHER_ENCRYPTED', false),
'useTLS' => env('PUSHER_TLS', false),
'cluster' => env('PUSHER_CLUSTER', 'mt1'),
],
],

'ably' => [
'driver' => 'ably',
'key' => env('ABLY_KEY'),
],

'redis' => [
'driver' => 'redis',
'connection' => 'default',
],

'log' => [
'driver' => 'log',
],

'null' => [
'driver' => 'null',
],

'http' => [
'driver' => 'http',
'base_url' => env('HTTP_BROADCASTER_API_ENDPOINT', 'localhost'),
'key' => env('HTTP_BROADCASTER_API_KEY', null),
'token' => env('HTTP_BROADCASTER_API_TOKEN', null),
'verify' => env('HTTP_BROADCASTER_API_VERIFY', true),

// Auth type can be null, 'basic', 'bearer', 'digest', 'key', 'jwt'
'auth' => env('HTTP_BROADCASTER_API_AUTH_TYPE', null),
],
],

];

Step 4: Configure Environment Variables

Add the necessary environment variables for your custom broadcaster in the .env file.

HTTP_BROADCASTER_API_ENDPOINT=https://example.com/api/broadcasting
HTTP_BROADCASTER_API_TOKEN=long-token
HTTP_BROADCASTER_API_AUTH_TYPE=bearer
HTTP_BROADCASTER_API_VERIFY=true

Step 5: Create an event

When wanting to trigger the following event upon creating a new user, ensure that a Laravel queue system is set up, as this event is queued due to the slow nature of HTTP/HTTPS requests. Learn more about Laravel Queues

<?php

namespace App\Events\User;

use Illuminate\Broadcasting\InteractsWithBroadcasting;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Contracts\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class Created implements ShouldBroadcast
{
use Dispatchable;
use SerializesModels;
use InteractsWithBroadcasting;

public function __construct(
public array $payload
){}

public function broadcastQueue(): string
{
return 'default';
}

public function broadcastAs(): string
{
return 'user.created';
}

public function channelName(): string
{
return 'admins';
}

public function broadcastOn(): array
{
return [
new PrivateChannel($this->channelName()),
];
}

public function broadcastConnections(): array
{
return ['http'];
}
}

Step 6: Broadcast event

The event above can be fired like so:

$payload = [
'id' => 1
'username' => 'emeka',
'email' => 'fake@test.com',
];

Created::dispatch($payload);

Step 7: In the second server or microservice

<?php //in api.php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\BroadcastingController;

Route::controller(BroadcastingController::class)->group(function(){
Route::post('broadcasting', 'broadcasting');
});
<?php // controller

namespace App\Http\Controllers;

class BroadcastingController extends Controller
{
public function broadcasting(string $event)
{
// handle the event
info($request->all(), ['event' => $event]);
}
}

--

--

Emeka Mbah
Emeka Mbah

Written by Emeka Mbah

Emeka is a seasoned software developer passionate about contributing to open-source projects.

No responses yet