Build an Interactive Messaging App with Stream, MML, Node and React

Message Markup Language (MML) enables you to build an interactive messaging experience. MML supports embedding elements as simple as a button to your message or as complex as date pickers and custom forms within your chat experience. MML also supports images, icons, and tables out of the box.

The goal for MML is to provide a standardized way to handle the most common use cases for message interactivity. MML can be extended into custom components using the MML React library.

MML for React

The first Stream SDK to support MML is the Stream Chat React SDK. This feature accepts an MML string and renders it as React components. To see specific examples of use cases for MML on React, read our docs for MML-React. Read more about MML in our chat docs.

Prerequisites

Basic knowledge of Node.js (Javascript) and React is required to follow this tutorial. This code is supposed to run locally on your machine. Make sure you have installed Node.js and Yarn. You also need to install create-react-app, which helps us kick off our React app.

You need to create an account for Stream and start your chat trial. Once you made your account, proceed to the dashboard and grab your app key and secret, we'll need them later.

Building the App

Our projects consist of a simple backend app written in Node.js, Express.js, and localtunnel to expose our localhost to the internet. The frontend app is a simple create-react-app project which uses Stream-Chat-React components that support MML out of the box. Let's start with our Frontend app.

Frontend

First, we need to create a new React application, install some dependencies, and then open the editor's frontend folder.

Open the src/App.css and replace its content with this:

Next, we need to choose a user id and generate a token for this user. Let's call our user "jim", grab your app secret from Stream Dashboard and head over to this the user token generator. In the user id field, enter jim and paste your app secret from the dashboard in the secret field. You now have a user token signed for this user. (Note that in production, you need to generate user token in your backend) Now we need to update our src/App.js file with this and put our API KEY from Stream Dashboard in line 8 and our generate user token in line 11:

Awesome! Our fully functioning chat application is ready! We can now see our app by running yarn start or npm start from the terminal. Open http://localhost:3000 in your browser and click on the "Create a New Channel" button to create the first channel for Jim.

Backend

Here things get interesting. We will create an API that accepts POST requests from the Stream Webhook system. Using webhooks allows you to integrate your server application with Stream Chat tightly. Our app will use the custom command webhook feature, and this will enable us to create interactive messages similar to how /giphy funk command works in Slack.

For our example app, we introduce a new command to our chat application that allows our users to create an appointment. When a user writes a message with /appointment [title], we will show a custom message to the user and follow a few steps to create an appointment in our server application. If you want to know more about how custom commands work best, see the Stream official documentation.

Let's create a new folder and start implementing our backend app:

We are going to create a basic Express app in the index.js file. We are using the localtunnel library, which allows us to tunnel our localhost API and expose it on the internet with a random public URL.

Now you can run your API by running node index.js in your terminal, and it should show you an output similar to this:

Note that the second URL is randomly generated every time you run your API. If you open it, you should see a JSON response like this {"message": "API is live!"} in your browser.

To integrate Stream with our backend, we need to get our API Key and Secret from Stream Dashboard similar to our frontend app. Once you got it, update your index.js file with the following code. We initialized our chatClient using our keys and created an express middleware to verify the request's integrity. That is a crucial step since our API is publicly accessible to everyone; we have to make sure the requests are coming from Stream. You can read more about this here.

In the next step, we will update the setupTunnelAndWebhook function to set up our webhook configuration and update our app's settings in Stream. First, we create our appointment command and update our Channel type with it. Next, we update the app configuration to forward commands to our server application.

Note: this step needs to be done only once for a production app. We are running this step every time we run the app as our public URL changes with each run for this tutorial.

So far, great! Finally, we can add the controller to handle the appointment command and respond to the user with our MML string. That is a rather complicated use case consisting of several steps to show the MML and Stream Webhooks' power.

You can see the full backend code here. Let's run our backend app by running node index.js and our frontend app by running yarn start and see how our app works:

  1. User writes a message with appointment command like /appointment Doctor
  1. Stream webhook calls our server application, we update the message with an MML Input component and ask for user phone number
  1. User enters the phone number and click on the submit button

  2. Our server application now receives another webhook call, which has a form_date object that includes the user's phone number. It stores the number and updates the message to show an MML Scheduler component

  1. User now selects a time slot and click on the submit button

  2. Another webhook call is received by our server application with the selected time slot. Now we make the message persistent, store the appointment in our database and update the message to show an MML AddToCalendar component that allows the user to add the appointment to their calendar of choice.

Final Thoughts

We successfully created a sample Chat application powered by Stream with custom commands, and MML React components.

MML is a powerful and flexible feature that allows us to support a wide range of use cases in our applications. Stream supports different types of webhooks.

For example, you can create a bot user in channels to respond with custom MML strings whenever a specific event happens or a new message is posted to a channel.

The full source code for this tutorial can be found in GitHub.