Мы завершаем эту серию, обращаясь к нескольким проблемам, которые решаются с помощью серверного кода.

Эта статья является продолжением серии, посвященной быстрым и простым решениям общих требований приложений.

Что интересно, только две из шести последних статей мы посвятили проблемам сервера. Вдобавок ко всему, мы не написали ни одной строчки серверного кода при создании нашего приложения для создания, чтения, обновления и удаления (CRUD). Однако есть пара проблем (требующих серверного кода), которые мы еще не решили.

Сторонние API

Надежные интерфейсные приложения могут делать многое из того, что мы привыкли полагаться на серверные приложения, например, для взаимодействия с различными API. В то же время есть ряд сценариев, когда это невозможно.

Например, некоторые сторонние API разработаны специально для работы на защищенном сервере; в частности, не в браузере. Например, для API Twitter требуется серверное приложение.

Транзакции

Вторая распространенная проблема - транзакции; как в транзакциях с базой данных.

Транзакции представляют собой предложение «все или ничего», в котором говорится, что каждая единица работы, выполняемая в базе данных, должна быть либо завершена полностью, либо не иметь никакого эффекта. Кроме того, система должна изолировать каждую транзакцию от других транзакций, результаты должны соответствовать существующим ограничениям в базе данных, а транзакции, которые завершились успешно, должны быть записаны в долговременное хранилище.

- Википедия (Транзакции с базой данных)

примечание: Firebase имеет отдельную концепцию, называемую транзакциями, которая решает несколько иную проблему.

Например, вспоминая наш пример «один ко многим» из предыдущей статьи:

Добавление нового файла влечет за собой внесение двух изменений в базу данных за одну транзакцию: добавление файла в files и добавление записи в children содержащей папки.

Поскольку мы не можем доверять интерфейсному приложению для обеспечения функции транзакций «все или ничего» (например, сбой браузера), нам необходимо реализовать это в приложении на стороне сервера.

Облачные функции

Облачные функции Google, тесно интегрированные с Firebase, представляют собой легкое решение для создания серверных приложений.

Облачные функции для Firebase позволяют автоматически запускать внутренний код в ответ на события, вызванные функциями Firebase и запросами HTTPS. Ваш код хранится в облаке Google и работает в управляемой среде. Нет необходимости управлять собственными серверами и масштабировать их.

- Google

Облачные функции могут запускаться при любом количестве событий; включая обработку HTTP-запросов.

Например, я работал над проектом, в котором интерфейсному приложению требовалось регулярно получать последний твит с определенным хэштегом. Поскольку API Twitter был разработан только для работы на серверах, я использовал Cloud Functions.

Существует два основных способа обработки HTTP-запросов с помощью облачных функций:

Поскольку я уже привык к Express, я использовал его для внутреннего приложения.

Облачные функции также могут запускаться при изменении базы данных. В примере с файлами и папками мы можем написать функцию, которая запускается добавлением к файлам и обновляет атрибут дочерних элементов папки.

Запросы

Поскольку мы сохраняем дизайн базы данных плоским и реляционным, мы обнаруживаем, что нам часто нужно возвращать выборку из списка. Например, предположим, что папки принадлежат пользователю, и нам нужно отображать только те, которые принадлежат определенному пользователю.

Используя функции сортировки и фильтрации Firebase, мы можем ограничить данные, которые возвращает дочерний прослушиватель, например, события child_added. Например:

...
export const ownerfoldersRef =
  database.ref('folders')
    .orderByChild('owner')
    .startAt('YiTpCoZEQXhjNnIC09kK1ArgrGo1')
    .endAt('YiTpCoZEQXhjNnIC09kK1ArgrGo1');
...

Проблема, однако, в том, что без дополнительной подготовки на стороне сервера эти запросы могут замедляться по мере роста базы данных.

Индексы

Проблему медленных запросов можно решить с помощью индексации ваших данных. Например, для запросов к папкам по владельцу мы будем использовать:

{
  "rules": {
    "folders": {
      ".indexOn": ["owner"]
    }
  }
}

Заключение

Написав эти статьи в течение последних нескольких недель, я чувствую, что почти готов к предстоящему через две недели хакатону. Надеюсь, вы тоже сочли это полезным.