Building a realtime chat app with Laravel using WebSockets
Tags: laravel
Published: 2022-07-18 09:50:37

---
title: Building a realtime chat app with Laravel using WebSockets
published: true
canonical_url: https://ably.com/blog/building-a-realtime-chat-app-with-react-laravel-and-websockets
description: 
tags: laravel
# cover_image: ![Building a realtime chat app with Laravel using WebSockets](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/psn30grrkupiuyavvqo7.png)
# Use a ratio of 100:42 for best results.
---

You use realtime communication every day. It is the simultaneous exchange of information between a sender and a receiver with almost zero latency. Internet, landlines, mobile/cell phones, instant messaging (IM), internet relay chat, videoconferencing, teleconferencing, and robotic telepresence are all examples of realtime communication systems.

In this tutorial, you’ll learn how to build a web based [realtime chat app] (https://hubs.la/Q01JtTqm0) using [Laravel](https://laravel.com/), [Ably](https://hubs.la/Q01JtTrm0) and [Vue.js](https://vuejs.org/). You’ll use Vue.js to build the frontend/UI and Laravel as a backend to interact with Ably Realtime APIs to facilitate realtime communication. By building this type of application, you’ll learn about the core concepts for building realtime apps using the Laravel-Ably integration.

Please note that you can use any frontend framework ([react](https://reactjs.org/), [angular](https://angular.io/), [next.js](https://nextjs.org/) etc.) to build the Laravel chat app and there is no dependency on any specific framework.

The source code for the project is available [in this GitHub repo](https://github.com/ably-labs/laravel-broadcast-app).

## Architecture of the realtime chat app

Before getting started, you should familiarize yourself with the tech stack that you’ll be using in this tutorial to build your chat application.

### Laravel  

[Laravel](https://laravel.com/) is a PHP-based web application framework with expressive, elegant syntax. The web development community loves Laravel because it provides an amazing developer experience and supports advanced concepts, like queues, dependency injection, unit testing, and integration testing. Laravel is a great choice for building realtime apps, and it already comes with support for Ably to "broadcast" your server-side Laravel events over a WebSocket connection.

### Ably  

[Ably](https://hubs.la/Q01JtTrm0) is a [pub/sub messaging platform](https://hubs.la/Q01JtTqK0) that powers synchronized digital experiences in realtime for millions of simultaneously connected devices around the world. Ably offers WebSockets, stream resume, history, presence, and managed third-party integrations to make it simple to build, extend, and deliver digital realtime experiences at scale. Ably makes use of different transports to make sure data is delivered in realtime.

### Vue.js

[Vue](https://vuejs.org/) is a frontend javaScript framework for building user interfaces. It builds on top of standard HTML, CSS, and JavaScript and provides a declarative and component-based programming model that helps you efficiently develop user interfaces, be they simple or complex.

### Laravel broadcasting

[Laravel broadcasting](https://laravel.com/docs/broadcasting) is a feature provided by Laravel as a way for a client (frontend) to publish and receive information in realtime via channels. A channel is a logical communication medium that helps to publish and subscribe to information over a WebSocket connection. There are 3 types of channels.

#### 1. Public channels

* The client doesn't need to be authenticated (logged in) to use public channels.
* The client can only subscribe to the data on this channel. To publish data, it needs to be done via the laravel-server (backend) i.e. `client1 => laravel => ably => client 2, client 3, client 4...`

#### 2. Private channels

* The client needs to be authenticated to use private channels.
* The client is directly able to publish and subscribe to data through Ably using [client-events](https://laravel.com/docs/broadcasting#client-events). i.e. `client1 => ably => client 2, client 3, client 4...`
* The client can also [publish data through laravel-backend](https://github.com/ably-labs/laravel-broadcast-app/blob/main/routes/api.php), as done for public channels.

#### 3. Presence channels

* These are similar to private channels, offering all of the features of private channels, as well as a way to register client presence on the channel.

**In this blog we will only look at public channels.** So, the architecture of the realtime chat app will look like this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jz1ctw9bs0jue0w4tevo.png)

The chat app uses [laravel](https://laravel.com/) + [ably-broadcaster](http://github.com/ably/laravel-broadcaster) and [Ably](https://hubs.la/Q01JtTrm0) at server side (backend) and [vue.js](https://vuejs.org/guide/introduction.html#what-is-vue) + [ably-laravel-echo](https://github.com/ably-forks/laravel-echo) at client side (frontend). 

Laravel-server is used for authenticating/authorizing clients and broadcasting information to ably on behalf of clients over a given channel. In the current example, since public channels don’t need any sort of authentication, it will only be used to broadcast information.

Clients (guest-users) use HTTP connection to **post a message with a channel-name** to Laravel-server. Laravel-server publishes the same message to Ably (on the same channel) using a named event. Ably is responsible for sending this information to clients (subscribed to the same channel) using the provided event over a WebSocket connection. Guest users consume this event on the client-side using the [Laravel Echo](https://github.com/ably-forks/laravel-echo) library.

Publishing a message on a channel is done using an event. **Events are the primary method of packaging a message on the channel**.

**In simpler terms**, when a message is published on a channel with an eventName, it will be received by a subscriber matching the same channelName and eventName.


## Setting up the environment  

Here is what we will need to get started.

### Prerequisites
* [PHP](https://www.php.net/manual/en/install.php) version >= 7.3
* [Node.js](https://nodejs.org/en/download/) version >=14.x.x

### Setting up the basic project structure
Execute the following command in the terminal to create a Laravel project.

```
composer create-project laravel/laravel ably-laravel-chat-app
```

Run the following commands to get the auto-generated app running

```
cd ably-laravel-chat-app
composer install
npm install
php artisan key:generate
php artisan serve // run in a separate terminal
npm run watch // run in a separate terminal 
```

Finally, open [localhost:8000](http://localhost:8000/) in your browser, and you’ll see your Laravel project running.

![Laravel app home page](https://ik.imagekit.io/ably/ghost/prod/2022/04/laravel-app-home-page.png?tr=w-1520)


## Setting up your Ably account  

To start, you need to [create an Ably account](https://hubs.la/Q01JtTwK0) if you don’t have one. Next, you need to grab the API key from the Ably dashboard:

1\. Visit your [app dashboard](https://hubs.la/Q01JtTBR0) and click **Create New App** with name **Chat-App**.
2\. Once the app has been created, go to the **API Keys** tab. Copy the first key with the name Root. Keep the key safe. The key shouldn't be exposed to the client code. 

That’s it. Your Ably account is ready to support realtime messaging.

## Setting up Ably broadcaster on Laravel  

Please follow the [Setup section](https://github.com/ably/laravel-broadcaster#setup) to configure the Ably broadcaster.

### Create PublicMessageEvent Class

To send events from Laravel to Ably, create an event file by running the following command in your terminal:

```
php artisan make:event PublicMessageEvent
```

This command will create a [PublicMessageEvent.php](https://github.com/ably-labs/laravel-broadcast-app/blob/main/app/Events/PublicMessageEvent.php) file in the [app/Events](https://github.com/ably-labs/laravel-broadcast-app/tree/main/app/Events) directory. Replace the content of the files with following:

```
<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class PublicMessageEvent implements ShouldBroadcast
{
    public $channelName;
    public $message;

    use Dispatchable, InteractsWithSockets, SerializesModels;

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

    /**
     * Get the channels the event should broadcast on.
     * https://laravel.com/docs/broadcasting#model-broadcasting-channel-conventions
     * 
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return [new Channel($this->channelName)];
    }
}
```

The code above specifies:

1\. The PublicMessageEvent class that implements the **ShouldBroadcast** interface.
2\. By default the class name is used as an event name. This means eventName will be **PublicMessageEvent**. You can change eventName using [broadcastAs](https://laravel.com/docs/9.x/broadcasting#broadcast-name).
3\. The [broadcastOn](https://laravel.com/docs/9.x/broadcasting#model-broadcasting-channel-conventions) method that is responsible for returning the channel/list of channels on which the event should broadcasted.

### Broadcasting using PublicMessageEvent class
To handle API requests from frontend, open the [routes/api.php](https://github.com/ably-labs/laravel-broadcast-app/blob/main/routes/api.php) file and add following route.

```
Route::post('/public-event', function (Request $request) {
    $channelName = $request->post('channelName');
    $message = $request->post('message');
    broadcast(new PublicMessageEvent( $channelName, $message ));
})->middleware('throttle:60,1'); // 60 requests/minute are allowed.
```

The code above specifies:

1\. A new API route to handle POST request from client. This API route will be available at **localhost:8000/api/public-event**.
2\. When called, the message is broadcasted to ably on the given channel with **eventName as PublicMessageEvent**.
3\. Throttle to 60 requests per minute for each IP address. It will return an error for requests exceeding the given limit. This is mainly to avoid spamming on public channels.

To check if the code is working correctly so far:
1\. Restart the server using `php artisan serve`. 
2\. Attach to channel `public:community` for new messages using the [Ably Dev Console](https://hubs.la/Q01JtTD80).
3\. Try sending a **POST** request to the **localhost:8000/api/public-event** endpoint using [curl](https://curl.se/docs/manual.html), [Postman](https://www.postman.com/) or any other tool with **channelName and message** as POST method body.

```
curl --location --request POST 'localhost:8000/api/public-event' \
--header 'Content-Type: application/json' \
--data-raw '{
    "channelName":"public:community",
    "message":"Hi there"
}'
```


4\. Check for this message in the [Ably Dev Console](https://hubs.la/Q01JtTD80) under the attached channel tab.

Next, we will look at setting up frontend to send and receive messages.


## Setting up Laravel Frontend  

Following packages need to be installed for proper communication with Laravel and Ably.

1\. [Laravel Echo](https://github.com/ably-forks/echo/): This JavaScript library allows clients/users to subscribe to channels and listen to the events sent from ably.
2\. [Axios](https://www.npmjs.com/package/axios): This package helps to make HTTP requests from client to laravel-server.

```
npm install @ably/laravel-echo ably axios
```

### Initialize Laravel-Echo
In the [resources/js/bootstrap.js](https://github.com/ably-labs/laravel-broadcast-app/blob/main/resources/js/bootstrap.js) file, add the following snippet as per the [Echo Setup Section](https://github.com/ably-forks/laravel-echo#installation).

```
import Echo from '@ably/laravel-echo';

window.Ably = require('ably');

// Create new echo client instance using ably-js client driver.
window.Echo = new Echo({
    broadcaster: 'ably',
});

// Register a callback for listing to connection state change 
window.Echo.connector.ably.connection.on((stateChange) => {
    console.log("LOGGER:: Connection event :: ", stateChange);
    if (stateChange.current === 'disconnected' && stateChange.reason?.code === 40142) { // key/token status expired
        console.log("LOGGER:: Connection token expired https://help.ably.io/error/40142");
    }
});
```

## Building the front-end UI  

Please take a look at [app.js](https://github.com/ably-labs/laravel-broadcast-app/blob/main/resources/js/app.js), [ChatComponent.vue](https://github.com/ably-labs/laravel-broadcast-app/blob/main/resources/js/components/ChatComponent.vue) and [MessageComponent.vue](https://github.com/ably-labs/laravel-broadcast-app/blob/main/resources/js/components/MessageComponent.vue) from the existing [repository](https://github.com/ably-labs/laravel-broadcast-app) under [resources/js/](https://github.com/ably-labs/laravel-broadcast-app/tree/main/resources/js/components) for building the UI for your chat app.

### Sending messages
In the [ChatComponent.vue](https://github.com/ably-labs/laravel-broadcast-app/blob/main/resources/js/components/ChatComponent.vue) file, you can see the `broadcastMessageOnPublicChannel` method is used for broadcasting data on a given public channel using axios.

```
broadcastMessageOnPublicChannel() {
    const message = this.message?.trim();
    if(!message)
        return;
    const publicChannelName = this.getActiveChannel().name;
    const broadcastUrl = window.location.origin + "/api/public-event";
    axios.post(broadcastUrl, { channelName : publicChannelName, message });
    this.message = null;
}
```

The code above specifies:

1\. **publicChannelName** is generally prefixed with `public:`.
2\. When **broadcastMessageOnPublicChannel** is called, it sends a message from the client to laravel-server at endpoint **/api/public-event** using axios.
3\. Axios sends a HTTP POST request with **channelName** and **message** as a request body.

### Receiving messages
In the [ChatComponent.vue](https://github.com/ably-labs/laravel-broadcast-app/blob/main/resources/js/components/ChatComponent.vue) file, the **listen** method describes handler for **PublicMessageEvent**.

```
Echo.channel(channelName)
.subscribed(() => // Do stuff when channel is attached )
.listenToAll(() => // Do stuff when any event is received )
.listen('PublicMessageEvent', (data) => {
    const channel = this.getChannelByName(channelName, 'public');
    this.updateBroadcastNotificationOnUI(channel, data)
})
```

The code above specifies:

1\. Public channel is created using **Echo.Channel(channelName)**.
2\. Actual publicChannelName is accessed using **Echo.Channel(channelName).name** and is prefixed with `public:`. i.e. If channelName is provided as **community**, internally it uses channel name as **public:community** while communicating with ably.
3\. The method `listenToAll` registers a handler which gets called for any event received.
4\. The method `listen` registers a handler for a specific **PublicMessageEvent** and updates the received message on the UI once called.

## Testing the chat app

To test your chat app, open the [localhost:3000](http://localhost:3000/) in at least two browser tabs. Join the public room in each tab and broadcast messages to each other. For more information, refer to Guest Mode under the [Usage Section](https://github.com/ably-labs/laravel-broadcast-app/#usage).

![How to test your chat app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4jvgrd242bdu9t50vynk.png)

## Conclusion  

That’s it! In this tutorial, you learned how to create a realtime chat app using Laravel and Ably for guest users. In a future blog, we will cover how to add chat functionality for authenticated (logged in) users. Depending on your requirements, you can also discover how to add more features to your chat app in the [Ably chat reference guide](https://hubs.la/Q01JtTJg0). 

We would love to hear about how you plan to use Ably in your applications. Join our [Discord server](http://go.ably.com/discord) and post your ideas for builds in the showcase channel to share, we’re currently giving out Ably tees to members who participate!