Thursday, 7 April, 2022 UTC


Summary

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 realtime public chat app using React.js, Laravel, and Ably. You’ll use React.js to build the frontend/UI and Laravel to interact with Ably Realtime APIs to facilitate realtime communication. Anyone on the internet would be able to use this app to post messages to a public chat room and talk anonymously with other connected users. By building this kind of application, you’ll learn about the relevant concepts for building applications that need real-time data transfer.
The entire code for the project is available in this GitHub repo.
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.

React.js

React.js is an open-source JavaScript library that is used for building reactive user interfaces and is often used for building client side rendered single-page applications. It is very easy to integrate it with TypeScript. Based on this tutorial, you can also perform the same set of actions in Next.js, which is a meta framework for developing universal React.js applications that are both client and server side rendered.

Laravel

Laravel 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 is a pub/sub messaging platform 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.
The architecture of the realtime chat app will look this:
Chat app workflow architectureSetting up your Ably account
To start, you need to create an Ably account if you don’t have one.
Next, you need to grab the API key from the Ably dashboard:
1. Visit your app dashboard and click Create New App.
2. Copy the private API key once the app has been created. Keep the key safe; you will use it to authenticate with the Ably service in Laravel and React.js.
Private key from the Ably dashboard

3. Enable the Pusher protocol support in your Ably app settings to use the Pusher protocol with Ably. You can find this feature in the Protocol Adapter Settings under the Settings tab. In case you’re asked about creating default namespaces, you should click No thanks.
Updating Ably settings

That’s it. Your Ably account is ready to support real-time messaging.
Setting up the environment
Here is what you’ll need to get started.

Prerequisites

- Node.js: This tutorial uses Node v16.14.0
- PHP: This tutorial uses PHP v7.4.3
- Composer: This tutorial uses Composer v2.1.0

Setting Up the Project

You’ll need a main directory that holds the code for both the frontend (React.js) and backend (Laravel). Open your terminal, navigate to a path of your choice, and create a directory chat-app-react-laravel-ably by running the following command:
mkdir chat-app-react-laravel-ably
In the chat-app-react-laravel-ably directory, you’ll install both Laravel and React.js projects.
Setting up the backend
Start by building the backend part of the chat app.
Then in your terminal, execute the following command to create a Laravel project in the backend directory:
composer create-project laravel/laravel backend
Next, once the above command has been executed, start your Laravel project by running the following commands in your terminal:
cd backend
php artisan serve
Finally, open localhost:8000 in your browser, and you’ll see your Laravel project running:
Laravel app home pageSetting up broadcasting
You’ll need to register the App\Providers\BroadcastServiceProvider before broadcasting any events. To do so, open the config/app.php file and then uncomment the BroadcastServiceProvider in the providers array:
'providers' => [
...
App\Providers\BroadcastServiceProvider::class,
...
]
This BroadcastServiceProvider class contains the necessary code for registering the broadcast authorization routes and callbacks.
Next, since you want to broadcast your events using Ably, install the Ably PHP SDK by running the following command in your terminal:
composer require ably/ably-php
You should also configure your Ably credentials in the config/broadcasting.php file. An example Ably configuration is already included in this file, allowing you to quickly specify your key.
Then add the ABLY_KEY environment variable to the .env file and replace your-ably-key with your registered Ably app’s key from the Ably dashboard:
ABLY_KEY=your-ably-key
Lastly, change the broadcast driver (BROADCAST_DRIVER) to ably in the .env file:
BROADCAST_DRIVER=ably
Your Laravel project is now ready to start broadcasting events.
Broadcasting events in Laravel with WebSockets
Before writing the code for broadcasting events to your React.js frontend, it is important to know how Laravel’s broadcasting works.
Laravel’s event broadcasting allows you to broadcast your server-side events to your client-side application using a driver-based approach to WebSocket. You can consume these events on the client-side using the Laravel Echo npm package.

Events are broadcast over channels. Your application can subscribe to these channels with/without authentication or authorization, depending on whether the channels are public or private.
To send events from Laravel, create an event file by running the following command in your terminal:
php artisan make:event MessageEvent
This command will create a MessageEvent.php file in the app/Events directory.

Next, open the app/Events/MessageEvent.php file and replace its content with the following code:
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Str;
// 1
class MessageEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
private $user, $message;
// 2
public function __construct($user, $message)
{
$this->user = $user;
$this->message = $message;
}
// 3
public function broadcastWith()
{
return [
'id' => Str::orderedUuid(),
'user' => $this->user,
'message' => $this->message,
'createdAt' => now()->toDateTimeString(),
];
}
// 4
public function broadcastAs()
{
return 'message.new';
}
// 5
public function broadcastOn()
{
return new Channel('public.room');
}
}
Here are the specifics in the above code:
1. You define a  MessageEvent  class that implements the `ShouldBroadcast` interface.
2. You define a constructor (__construct) for the MessageEvent class to which you’ll pass the user ($user) and message  $message) variables when creating the MessageEvent event object.
3. You define a broadcastWith method that returns the array of data related to the message you want to broadcast. By default, all an event class’s public properties are automatically serialized and broadcast as the event’s payload. So this method gives you more control over the data you broadcast over the event’s channels.
4. You specify the broadcast name as message.new by defining a broadcastAs method. This method is not required because, by default, Laravel broadcasts the event using the event’s class name.
5. You define a broadcastOn method that is responsible for returning the channels on which the event should broadcast. In this case, the event would be broadcast on a public channel (Channel) named public.room. If you want to broadcast an event on a private channel, you use PrivateChannel instead of Channel.
Receiving requests from the React.js frontend
In this chat app project, the frontend will send a POST request to the Laravel backend. Upon receiving the request, Laravel will launch the MessageEvent event and broadcast the event using the Ably-specified broadcast driver.
To receive API requests from the frontend, open the routes/api.php file and replace its content with the following code:
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Events\MessageEvent;
// 1
Route::post('new-message', function (Request $request) {
// 2
event(new MessageEvent($request->user, $request->message));
return 'ok';
});
In the above code, here are the specifics:
1. You define an API route (`new-message`) to which you would be able to send POST requests. This API route will be available at localhost:8000/api/new-message].
2. You fire the MessageEvent event by passing the user ($request->user) and message ($request->message) variables as arguments.
Finally, to check if the code is working correctly so far, try sending a POST request to the localhost:8000/api/new-message endpoint using Postman or any other tool and sending the user and message as a payload. You should receive an ok response. If you do not receive an ok response, please carefully review the steps of the tutorial to ensure that you have followed them correctly.
That’s it for the Laravel part of the project. Next, you need to set up a React.js app to listen to the events being broadcast by the Laravel backend.
Setting up the React.js frontend
Now that you have completely set up your Laravel project, it’s time to build the React.js frontend app.
Since your current terminal window is serving the Laravel project, open another terminal window and execute the following command from the project’s root directory (chat-app-react-laravel-ably) to create a React.js project using the famous create-react-app:
npx create-react-app frontend
Finally, once the installation is complete, navigate to the frontend directory and start the React.js development server by running the following commands in your terminal:
cd frontend
npm start
This command will start the development server on port 3000 and take you to localhost:3000. The first view of the React.js website will look like this:
React.js website home pageInstalling frontend packages
You will need to install the following packages to create the frontend of the chat app:
- axios: This package allows you to make HTTP requests in your client-side application.
- Laravel Echo: This JavaScript library allows you to subscribe to channels and listen to the events being broadcast by your server-side broadcasting driver.
- pusher-js: You might think “why do I need pusher-js when I am using Ably to broadcast my events?” This is because Ably includes a Pusher protocol adapter that lets you use the Pusher protocol when listening for events in your client-side application.
Shut down the React.js development server by pressing Control-C and then execute the following command to install the required modules for your React.js app:
npm install axios laravel-echo pusher-js
Once the installation is complete, add the REACT_APP_MIX_ABLY_PUBLIC_KEY environment variable to the .env file. Your Ably public key is the portion of your Ably key that occurs before the : character:
REACT_APP_MIX_ABLY_PUBLIC_KEY=<your-ably-public-key>
REACT_APP_API_BASE_URL=http://localhost:8000/api
In the above configuration, you have specified REACT_APP_MIX_ABLY_PUBLIC_KEY and REACT_APP_API_BASE_URL. It is important to prefix your environment variables with REACT_APP_ so that they can be used by create-react-app.
Setting up Laravel Echo
You must set up Laravel Echo before it can help you subscribe to channels and listen for events. Open the src/App.js file and input the following code:
// 1
import PublicMessagesPage from './components/PublicMessagesPage';
// 2
export default function App() {
return <PublicMessagesPage />;
}
In the above code, this is what’s happening:
1. You import the  PublicMessagesPage  component.
2. You render the PublicMessagesPage component in the `App` component.
Building the frontend UI
You will now build the public chat home page and message box component that comprise the app’s frontend UI.

Building the public chat home page

To begin, create a components directory in the src directory. Then, in the components directory, create a PublicMessagesPage.js file and add the following code to it:
// 1
import React, { useState, useEffect } from 'react';
import Axios from 'axios';
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
import Messagebox from './Messagebox';
// 2
export default function PublicMessagesPage() {
// 3
const [user, setUser] = useState('');
const [message, setMessage] = useState('');
const [messages, setMessages] = useState([]);
async function handleSendMessage(e) {
// TODO
}
// 4
return (
<div>
<div>
<div>
<h1>Public Space</h1>
<p>Post your random thoughts for the world to see</p>
</div>
<div>
{messages.map((message) => (
<Messagebox key={message.id} message={message} />
))}
</div>
<div>
<form onSubmit={(e) => handleSendMessage(e)}>
<input
type="text"
placeholder="Set your username"
value={user}
onChange={(e) => setUser(e.target.value)}
required
/>
<div>
<input
type="text"
placeholder="Type your message..."
value={message}
onChange={(e) => setMessage(e.target.value)}
required
/>
<button onClick={(e) => handleSendMessage(e)}>Send</button>
</div>
</form>
</div>
</div>
</div>
);
}
This is what’s happening in the above code:
1. You import the required NPM packages.
2. You define the PublicMessagesPage functional component.
3. You define the state variables for PublicMessagesPage component using useState React hook:
-   user  stores the current user’s name
- message  stores the currently typed message
- messages  stores all the messages sent and received in the present session
4. You return the JSX template for the Public Messages Page.
> Note: The styling part of the app was skipped because understanding the functionality is more important for now and styling the app can be done according to your preference.
Next, you need to implement the Messagebox component.

Creating the message box component

To start, in the components directory, create a Messagebox.js file and add the following code to it:
// 1
export default function Messagebox({ message }) {
const formatDate = (value) => {
if (!value) return '';
return new Date(value).toLocalTimeString();
};
// 2
return (
<div>
<div>
<p>
<b>{message.user}</b>
</p>
<p>{message.message}</p>
<p>{formatDate(message.createdAt)}</p>
</div>
</div>
);
}
Here are the above code’s specifics:
1. You define a stateless functional component  Messagebox  and pass the  message   object as its parameter.
2. You return the HTML template for the  Messagebox  component.
At this point, save your progress and restart the React.js development server by running the following command in your terminal:
npm start
Visit localhost:3000, and based on the way you’ve styled your app, you’ll get something like this:
Chat app home pageSending messages
With the frontend UI established, the next step is to enable message sending. In the src/components/PublicMessagesPage.js file, you need to implement the handleSendMessage method. So start by updating the handleSendMessage function by adding the following code:
async handleSendMessage(e) {
// 1
e.preventDefault();
// 2
if (!user) {
alert('Please add your username');
return;
}
// 3
if (!message) {
alert('Please add a message');
return;
}
try {
// 4
await Axios.post('/new-message', {
user: user,
message: message,
});
} catch (error) {
console.error(error);
}
}
Here are the specifics for the above code:
1. You use the `e.preventDefault()` method to prevent the page from reloading as the form is submitted.
2. You validate whether the user state variable is empty. If empty, you alert the user to add their username.
3. You also validate whether the message state variable is empty. If empty, you alert the user to add a message.
4. You make a POST request (Axios.post) to the /new-message API endpoint after the validation is successful and send the user and message state variables as a payload.
Once a POST request is made to the Laravel endpoint, the MessageEvent event is fired. So next, you need to listen to this event in your React.js app.
Listening to events
To listen to the events, add the useEffect React hook to the PublicMessagesPage component in the src/components/PublicMessagesPage.js file:
// 1
useEffect(() => {
// 2
Axios.defaults.baseURL = process.env.REACT_APP_API_BASE_URL;
// 3
const echo = new Echo({
broadcaster: 'pusher',
key: process.env.REACT_APP_MIX_ABLY_PUBLIC_KEY,
wsHost: 'realtime-pusher.ably.io',
wsPort: 443,
disableStats: true,
encrypted: true,
});
// 4
echo
.channel('public.room')
.subscribed(() => {
console.log('You are subscribed');
})
// 5
.listen('.message.new', (data) => {
// 6
setMessages((oldMessages) => [...oldMessages, data]);
setMessage('');
});
}, []);
In the above code, here are the specifics:
1. You define the  useEffect React hook that is called immediately after the `PublicMessagesPage` component is mounted.
2. You define the base URL (Axios.defaults.baseURL) for the Axios package on which it makes the HTTP requests to the backend API.
3. You create a new Echo instance and subscribe to the public.room channel on the backend.
4. You subscribe to the public channel (public.room) on which the events are being broadcast.
5. You listen to the message.new event and pass the callback function that receives the data sent as the event response. Since you have defined a custom broadcast name using the broadcastAs method, you need to add the . character before the event name. This addition instructs the Echo not to prepend the application’s namespace to the event name.
5. You update the messages state variable by adding the new message payload (data) to the existing messages (oldMessages) in the state.
Finally, save your progress and reload the React.js development server. You’ll now be able to send messages to the public chat room:
Sending messages in chat app‌‌Testing the app
To test your chat app, open the localhost:3000 in at least two browser tabs or windows and try sending messages by setting different usernames. Here’s how the app will behave:
Message sending between two usersConclusion
That’s it! In this tutorial, you learned how to create a real-time chat app using React.js, Laravel, and Ably. You also tested if your app was functioning correctly. Depending on your requirements, you can discover how to add more features to your chat app in the awesome Ably documentation. It’s exciting to hear about how you’ll use Ably in your applications.

The entire source code for this tutorial is available in this GitHub repository.