Being able to communicate with a group of people in real-time over chat is one of the most powerful features of modern messaging. Real-time messaging with groups of people can have live general discussions across the board as though it were a one-to-one chat, which makes sharing general information fast and easy. In this tutorial, we’ll build a chatroom application using Laravel, Vue.js, and Stream Chat.
Prerequisites
To follow along with this tutorial, a basic understanding of Laravel, Vue.js, and JavaScript is required. Also, this tutorial assumes you have the Laravel installer installed on your computer. Lastly, a Stream Chat account is required. You can sign up for a free 14-days trial (no credit card required).
What we’ll be building
In this tutorial, we’ll be building a chat room where users can join and chat with other users in real-time. Users will be automatically added to the chatroom at the point of registering on our application. Below is a quick demo of what our finished application will look like:
Getting our Stream Chat keys
To start using the Stream Chat API, we need to have our Stream Chat API keys. Create an account or log in if you already have an account. Once you’re logged in, you can save the keys from the app that's automatically created for you. Or, if you prefer, on your dashboard, create a new app by clicking the Create App button.
Once that is done, you should see an API Key, Secret, and App ID of your newly created application.
Take note of these keys as we’ll be needing them shortly.
Getting Started
To get started, we’ll be using the Laravel installer to create a new Laravel application. Run the following command to create a new Laravel application:
laravel new laravel-stream-chatroom && cd laravel-stream-chatroom
Once the application is created, we need to install the NPM dependencies (because Vue.js and Bootstrap come pre-packed as an NPM dependency). In your terminal run:
[https://gist.github.com/ammezie/ed72b3580eb3217539aed9a880b89e04]
For this tutorial, we'll be concerned with the resources/js
directory, which is where Vue.js will be instantiated. Here is a tutorial on building a real-time chat app with Vue.
Now, we can start building our application.
Building the backend
As already mentioned, the backend will be built with Laravel, since we already have a new Laravel project, let’s start fleshing it out. For our chatroom application, we want users to register before they are granted access to the chatroom, so we’ll start by adding authentication. Laravel makes this seamless. In Laravel 6, the authentication scaffolding is extracted to a separate package, so we need to install the following package:
composer require laravel/ui --dev
Once that’s installed, we can run the command below to create the authentication scaffolding:
php artisan ui vue --auth
Now, we can run the default migrations that Laravel created for us:
php artisan migrate
Note: Make sure you have set up your database before running the migrations.
Let’s add our Stream Chat keys to .env
:
// .env MIX_STREAM_API_KEY=YOUR_STREAM_API_KEY MIX_STREAM_API_SECRET=YOUR_STREAM_API_SECRET
Remember to update the YOUR_STREAM_API_KEY
and YOUR_STREAM_API_SECRET
placeholders with your actual API details. To be able to access these environment variables in our frontend as well, we need to prefix them with MIX_
.
Let’s start our application to make sure everything is working as expected:
php artisan serve
Now, we have Laravel default authentication in place. Let’s make some modifications to suit our application needs. Add the following code inside app/Http/Controllers/Auth/RegisterController.php
:
// app/Http/Controllers/Auth/RegisterController.php // first import StreamChat PHP client use GetStream\StreamChat\Client as StreamClient; protected function registered($user){ $client = new StreamClient(env("MIX_STREAM_API_KEY"), env("MIX_STREAM_API_SECRET"), null, null, 9); $username = explode('@', $user->email)[0]; // create the user on Stream Chat $client->updateUser([ 'id' => $username, 'name' => $user->name, ]); // create channel $channel = $client->Channel("messaging", "chatroom"); // channel is created by `admin` user $channel->create('admin'); // then add the newly registered user as a member $channel->addMembers([$username]); }
The registered()
function gets called once a user has registered within our application.
In addition to creating users on our end, we want to also create the users in Stream Chat, so we use the updateUser()
function on the StreamClient
instance.
We will need to extract a username from the user's email address, which we then use as the users id
on Stream Chat and name as the user's name.
Also, we create a channel on Stream Chat of the type messaging
, which we call chatroom
. Using the create()
, we set the creator of the channel to an admin
user. Lastly, we add the newly registered user as a member of the channel.
Now, whenever a user registers within our application, they’ll automatically be added to the channel.
Before we move on, let’s install the Stream Chat PHP client:
composer require get-stream/stream-chat
Our final task on our backend will be to send an authentication token from our backend to the frontend. This is what Stream Chat will use to authenticate the origin of the request and if the frontend is allowed to have the information.
Create a ChatController.php
inside the app/
H
ttp
/
Controllers
directory and add the following to it:
// app/http/Controllers/ChatController.php <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use GetStream\StreamChat\Client as StreamClient; class ChatController extends Controller { /** * Generate token for clientside use */ public function generateToken(Request $request) { $client = new StreamClient(env("MIX_STREAM_API_KEY"), env("MIX_STREAM_API_SECRET"), null, null, 9); return response()->json([ 'token' => $client->createToken($request->user_id) ]); } }
The generateToken()
generates a token using the user’s id and sends it back to the client-side. To have access to this method, we need to create a route for it.
Open up routes/api.php
and add the following to it:
// routes/api.php Route::post('/generate-token', 'ChatController@generateToken');
Now our backend work is done. Let’s implement the functionality of our frontend to start chatting.
Building the frontend
Let’s go ahead and build the frontend of our application. Laravel supports Vue.js out of the box. So everything is already set up. To be able to use Stream Chat on our Vue.js frontend, we need to install the JavaScript client. Run the following in your terminal:
npm install stream-chat
Next, we need to create and initialize our components. Open resources/js/app.js
and add the following code to it:
// resources/js/app.js Vue.component('chat-room', require('./components/ChatRoom.vue').default);
We haven’t created our component yet, so technically, this will throw an error if we start up our application. Let’s build the component now.
In the resources/js/components
directory, create a ChatRoom.vue
file and add the following code to it:
// resources/js/components/ChatRoom.vue <template> <div class="container"> <div class="row"> <div class="col-md-3"> <div class="card"> <div class="card-header">Members</div> <div class="card-body"> <ul class="list-group list-group-flush"> <li class="list-group-item" v-for="(member, id) in members" :key="id" >{{ member.user.name }}</li> </ul> </div> </div> </div> <div class="col-md-9"> <div class="card"> <div class="card-header">Chats</div> <div class="card-body"> <dl v-for="message in messages" v-bind:key="message.id"> <dt :class="{ 'text-right': message.user.id === username }">{{ message.user.name }}</dt> <dd :class="{ 'text-right': message.user.id === username }">{{ message.text }}</dd> </dl> <hr /> <form @submit.prevent="sendMessage" method="post"> <div class="input-group"> <input type="text" v-model="newMessage" class="form-control" placeholder="Type your message..." /> <div class="input-group-append"> <button class="btn btn-primary">Send</button> </div> </div> </form> </div> </div> </div> </div> </div> </template> <script> import axios from "axios"; import { StreamChat } from "stream-chat"; export default { name: "ChatRoom", props: { authUser: { type: Object, required: true } }, data() { return { token: null, channel: null, members: [], client: null, messages: [], newMessage: "" }; }, computed: { username() { return this.authUser.email.split("@")[0]; } }, async created() { // gerenrate clientside token from server await this.getToken(); await this.initializeStream(); await this.initializeChannel(); }, methods: { async getToken() { const { data } = await axios.post("/api/generate-token", { user_id: this.username }); this.token = data.token; }, async initializeStream() { this.client = new StreamChat(process.env.MIX_STREAM_API_KEY, { timeout: 9000 }); await this.client.setUser( { id: this.username, name: this.authUser.name }, this.token ); }, async initializeChannel() { this.channel = this.client.channel("messaging", "chatroom"); const { members, messages } = await this.channel.watch(); this.members = members; this.messages = messages; // listen for new messages this.channel.on("message.new", event => { this.messages.push({ text: event.message.text, user: event.message.user }); }); // listen for when a new member is added to channel this.channel.on("member.added", event => { this.members.push(event); }); }, async sendMessage() { await this.channel.sendMessage({ text: this.newMessage }); this.newMessage = ""; } } }; </script>
The UI of this component is made up of two parts: a list of channel members and the chat itself. The component accepts a required prop called authUser
, which is the currently authenticated user. Just as we need on the backend, we create a username
computed property, which simply extracts the username from the authenticated user’s email address. We want to perform some logic as soon as the component is created, so we wrap them inside a dedicated method and add them in the created
life cycle hook.
The getToken
()
is used to get the token from our backend, this token will be used to authenticate our connection with Stream Chat from the frontend. Next, in the initializeStream()
, we instantiate a new instance of Stream Chat. Then we specify the current user with setUser()
, which accepts an object of the user (here, we are only specifying the user’s id and name) and the user token.
The initializeChannel()
initializes the channel we created on the backend earlier. Then we fetch the channel’s members and messages and subscribe to the channel for any future activities on it. Since we are subscribed to this channel and listening for events, we want to update the chats once messages are added. We also want to update the member list whenever a new member joins the channel. This is where Stream Chat events come into play. First, we listen for the message.new
event, and update the messages
array with the new message, which is passed along with the event. Next, we listen for the member.added
event, and update the members
array with the newly added member.
The sendMessage()
is called whenever the chat form is submitted. Using the channel
instance created earlier, we call a sendMessage()
on it, which accepts an object of the message content. In our case, we are only sending a text. Then, we clear the form field.
Finally, we need to display the chat room component and pass to it the authUser
props. In Laravel, logged in, users are redirected to the /home
route, which uses the home
view. Open resources/views/home.blade.php
and update it as below:
// resources/views/home.blade.php @extends('layouts.app') @section('content') <chat-room :auth-user="{{ auth()->user() }}"></chat-room> @endsection
Testing the Application
Now, let’s test what we’ve been building so far. First, let’s make sure our application is still running:
php artisan serve
Navigate to http://127.0.0.1:8000 and open the application in three separate browser windows and login and start chatting.
Conclusion
In this tutorial, we have explored how to make a functional chatroom using Laravel, Vue.js, and Stream Chat. The knowledge from here can be used to create more complex group chat and real-time applications.
Stream offers a real-time chat API and a wide variety of other features that can be useful in creating truly mature chat and in-app messaging solutions. You can learn more about Stream Chat here.
The complete code for this tutorial is available on GitHub.