Во многих мобильных и веб-приложениях требуется создать чаты. Мы говорим не о надоевших всплывашках для общения с оператором: обычно они предоставляются As a service и подключаются одной строчкой кода.

Я говорю о полноценных чатах, в том числе групповых, где пользователи могут общаться между собой, отправлять медиа, использовать видеозвонки. Подчеркну, что речь идёт о приложениях, где чат является лишь малой частью ПО, а не его основным функционалом — не требуется offline режим, E2E шифрование, и многие другие вещи (как в мессенджерах Telegram, WhatsApp и т. д.).

Технически любой чат состоит из следующих вещей: UI, транспортный уровень, сервер, хранилище. В качестве транспорта для чатов лучше всего подходят веб-сокеты. Хранилищем может выступать любая база данных, сервер должен обеспечивать права доступа и API для клиентов.

Стандартных решений для чатов множество, одним из наиболее популярных и проверенных временем можно назвать Jabber (XMPP), имеющий множество реализаций. Также популярны кастомные решения на основе Node.js и socket.io, а также Firebase. В этой статье не будет сравнений разных подходов, а пойдет речь о реализации чатов с помощью Firebase realtime database.

Делаем чаты с Firebase realtime database

Firebase realtime database (RDB) — nosql база данных, размещённая на серверах Google  и доступная по сети по протоколу Websocket, есть SDK для практически всех платформ и языков. Стоит отметить, что Firebase недоступен в Китае и ряде других стран, где сервера Google заблокированы фаерволами.

RDB покрывает 3 из 4 компонентов любого чата: транспорт, сервер, хранилище. Фактически фронтенд напрямую соединяется с базой данных и может как читать так и записывать туда документы (сообщения, пользователей, комнаты чатов). Доступ пользователя до документов регулируется Security rules. При соединении с базой данных клиент авторизуется по JWT токену, в котором зашит userId или другая информация о нём, и с помощью выражений security rules, можно описать, имеет ли он доступ до того или иного документа или коллекции. Также security rules используются для индексации документов.

Вот пример security rules из опенсорсного проекта Firechat:

Смысл этих выражений в том, что пользователь может получить доступ до объекта внутри коллекции messages только в том случае, если uid из его JWT токена есть в списке authorizedUsers соответствующей комнаты чата

Сама схема базы данных в Firebase состоит из следующих коллекций, и, конечно, зависит от бизнес-требований к чату. Примерный вид схемы:

Пример авторизации в RDB с помощью Javascript SDK:

JWT токен можно сгенерировать на бэкенде вашего приложения и отдавать пользователю. Например, в методе login, вместе с токеном вашего сервера.

Пример генерации JWT-токена с помощью SDK PHP:

clientEmail и privateKey берутся из сервисного файла Firebase.

Примеры интеграции с Firebase на фронтенде

Загрузка списка id комнат пользователя:

Для загрузки сообщений из комнаты чатов:

Для записи сообщения в чат мы просто записываем сообщение в таблицу messages новый объект:

Частно нужно взаимодействовать с чатами на сервере (например, отправлять пуш нотификации при отправке нового сообщения). Используя Admin SDK, можно подписаться на любые новые сообщения в базе, минуя security rules. Вот пример подписки на новые сообщения в комнате чата:

Из минусов Firebase RDB можно отметить очень ограниченный набор функций по поиску данных. Например, полноценный поиск по сообщениям сделать там невозможно, для этого нужно либо вести двойную запись сообщений (как вариант, в Elasticsearch или Algolia). Двойную запись можно сделать как на своем сервере в событии child_added, так и с помощью Firebase cloud functions. Пример интеграции с Algolia.

Firebase имеет очень хорошую документацию и позволяет сделать кастомные чаты с практически любым функционалом. Из главных его плюсов — простота и отсутствие забот об инфраструктуре. А о том, как добавить в чаты видеозвонки, мы рассказывали в прошлой статье.