Broadcasting with Laravel, Passport, Pusher & Vue.js

Mark de Vries
Vue.js Developers
Published in
4 min readJun 18, 2019

Our omnichannel commerce platform Skata makes heavily use of realtime data within the backoffice. While many employees are collaborating in the interface it’s important that everybody is working with data about products, orders, stock levels and reporting that is realtime: we guarantee a single source of truth.

Skata. The omnichannel commerce platform that covers it all.

Tech Stack

We make use of the following stack for all our API’s and clients that don’t need SSR. For this tutorial we take an installed Laravel 5.8 application with Passport 7.3 as a starting point whereby we use token based authentication.

Laravel

1.1) Install Pusher library

composer require pusher/pusher-php-server "~3.0"

1.2) Add Pusher credentials

Within the .env file set Pusher as Broadcast Driver and add your Pusher credentials after creating an account at Pusher

BROADCAST_DRIVER=pusherPUSHER_APP_ID=123456
PUSHER_APP_KEY=kj2nrqlqkn329q2fnaas
PUSHER_APP_SECRET=kj234adfad9f2lqnra21
PUSHER_APP_CLUSTER=eu

1.3) Enable BroadcastServiceProvider

Enable the BroadcastServiceProvider in config/app.php. By default this Service Provider is commented out and hereby inactive.

App\Providers\BroadcastServiceProvider::class,

1.4) Adjust BroadcastServiceProvider.php

Adjust app/Providers/BroadcastServiceProvider.php by specifying the auth:api middleware and api prefix.

/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Broadcast::routes([
'middleware' => 'auth:api',
'prefix' => 'api'
]
);
require base_path('routes/channels.php');
}

1.5) Add channel route

We add a channel to routes/channels.php. In our case we name the channel backoffice-activity. We will specify this name in the Events that we will create in one of the following steps.

Broadcast::channel('backoffice-activity', function () {
return Auth::check();
});

1.6) Create an Event

In our platform most of the broadcasting is related to Events that are fired. We create an Event called PurchaseOrderCreated: an event that we fire after a PurchaseOrder is created successfully.

php artisan make:event PurchaseOrderCreated

The command will create the following file: app/Events/PurchaseOrderCreated.php in which we have to make some adjustments:

Let the event Broadcast by adding implements ShouldBroadcast to the class:

class PurchaseOrderCreated implements ShouldBroadcast

We want to pass on data to the client in order to directly update the data within the Vue application when the event is received. We provide the data to the event by passing the Model instance that is related to the event: in our case a single PurchaseOrder that is recently created.

public $purchaseOrder;/**
* Create a new event instance.
*
* @return void
*/
public function __construct($purchaseOrder)
{
$this->purchaseOrder = $purchaseOrder;
}

Specify the private channel on which the event should broadcast on:

/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('backoffice-activity');
}

Specify the broadcast name of the event:

/**
* The event's broadcast name.
*
* @return string
*/
public function broadcastAs()
{
return 'purchaseOrder.created';
}

1.7) Fire the event

Optional: Make a (temporary) route to test firing the event:

Route::get('/debug/events', function () {
$purchaseOrder = App\PurchaseOrder::create([
supplier_id => 1,
expected_at => '2019-08-03 12:00:00'
]);
event(new App\Events\PurchaseOrderCreated($purchaseOrder));
});

Vue.js

Install vue-pusher within your Vue.js application:

yarn add vue-pusher

2.1) Initialise Pusher

Within the client we want to subscribe to the backoffice-activity private channel and receive realtime messages. The API base url is defined in the .env file within the root of the Vue application.

VUE_APP_API_URL=https://backoffice-api.skata.test/apiVUE_APP_PUSHER_APP_KEY=kj2nrqlqkn329q2fnaas
VUE_APP_PUSHER_APP_CLUSTER=eu

After logging in, our token, generated via Passport, is stored via vuex in the auth store module. We use this token in an Authorization header, similar to a request to the API via axios. In this example, we initialise Pusher in the src/main.js file:

import Vue from 'vue'
import VuePusher from 'vue-pusher'
Vue.use(VuePusher, {
api_key: process.env.VUE_APP_PUSHER_APP_KEY,
options: {
cluster: process.env.VUE_APP_PUSHER_APP_CLUSTER,
encrypted: true,
authEndpoint: `${process.env.VUE_APP_API_URL}/api/broadcasting/auth`,
auth: {
headers: {
Authorization: `Bearer ${store.state.auth.token}`
}
}
}
})

2.2) Subscribe to channel

Subscribe to the private-backoffice-activity channel. Be aware, a private channel will always be prefixed with private-

const channel = this.$pusher.subscribe('private-backoffice-activity')

2.3) Bind event listener

Bind event listener to the purchaseOrder.created event in the component or view of your choice.

channel.bind('purchaseOrder.created', ({ purchaseOrder }) => {
this.$notify({
type: 'info',
text: `New purchase order (${purchaseOrder.id}) created`
})
this.latestPurchaseOrder = data
})

Within the callback you can choose the follow up actions based on the received event. This can be a simple notification (eg with vue-notification) or an update to existing data based on the data received via the event.

Feedback

If you have any feedback on the process, code structure or my writing, please feel free to contact me at mark@skata.io

--

--