
Next.js встречает firebase и mobx | III
Эпизод 3 | правила проверки и чтение / запись данных
Введение
В последних двух эпизодах мы создали базовое приложение next.js и аутентифицировали наших пользователей через провайдеров firebase oauth. Это было довольно скучно, поскольку у нас даже нет данных в нашей базе данных: «(Так что давайте это изменим!
Firebase полностью работает на стороне клиента, но, поскольку мы не можем доверять пользователям, мы должны определить правила проверки на сервере, чтобы предотвратить злонамеренное использование. Правила проверки как-то сложно читать и писать, но firebase предоставляет инструмент для написания правил на более понятном языке и их повторной компиляции в большой файл json. Он называется bolt, а в бета-версии вроде… навсегда. Я много использовал его, и у меня никогда не было проблем, поэтому я считаю, что он достаточно стабилен, чтобы рекомендовать его в этой статье.
Определение правил проверки
Итак, давайте сначала установим firebase-tools и firebase-bolt:
npm install -g firebase-bolt # needed for compiling bolt npm install -g firebase-tools # needed for deploying changes
И добавляем необходимые файлы:
// file: firebase.json
{
"database": {
"rules": "database.rules.bolt"
}
}
// file: database.rules.bolt -> we'll refine this later
path / {
read() {true}
write() {true}
}
Вы также можете запустить firebase init, чтобы запустить интерактивную оболочку, которая создает для вас файл firebase.json. Имейте в виду, что хостинг на firebase не будет работать, поскольку у вас нет серверной части, которая требуется next.js для SSR.
Теперь у вас должна быть возможность запустить firebase deploy, и вам будет предложено выбрать проект по умолчанию. После этого должна быть развернута база данных (с доступом для чтения и записи для всего)!

Так что давайте уточним наши правила!
Итак, теперь мы проверяем, аутентифицирован ли пользователь, который пытается писать, и соответствует ли его uid тому {userid}, которому он хочет писать. У нас есть два правила, так как мы хотим, чтобы пользователь мог читать все свои сохраненные хэши, обращаясь к ref /hashes/{uid}, и получать доступ к отдельным хешам через ref /hashes/{uid}/{hashId}.
Мы также могли бы заархивировать это без второго правила, но я планирую реализовать функцию общего доступа позже, изменив правило на hashes/{uid}, так что эта настройка кажется полезной для будущих требований.
Эта настройка довольно удобна, но не идеальна, поскольку теперь пользователи могут хранить в hashes/{uid}/{id}. все, что захотят. Чтобы этого не произошло, мы еще немного уточним наши правила для болтов.
Теперь мы заставляем каждый hashes/{uid}/{id} быть из типа Hash, который состоит из 3 свойств:
CurrentTimestamp: число, содержащее текущую временную метку в firebase server-time (псевдоним сейчас).
InitialTimestamp: число, содержащее либо текущую метку времени, либо то, что было введено ранее. Это очень похоже на javascript с небольшими отличиями: мы передаем this в качестве ссылки и вместо того, чтобы возвращать значение, мы напрямую изменяем его внутри функции.
text: - это строка, похожая на то, что вы ожидаете на любом другом языке.
С внесенными выше изменениями теперь мы можем хранить только следующие структуры данных:
{
text: 'sometext',
created: 121414141,
modified: 14141444
}
У нас пока нет никаких проверок свойства text, но мы сделаем это позже, когда приложение будет развиваться - на данный момент достаточно проверки, давайте сохраним некоторые данные!
Несколько слов о валидации
Всегда следует выполнять проверку на стороне сервера - даже если вы доверяете своим пользователям, чего, конечно же, делать не следует! Проверка помогает поддерживать согласованность данных, даже если у вас есть программные ошибки.
Представьте, что в приведенном выше примере у нас где-то есть ошибка, которая вставляет {text: sometext} вместо полноценного объекта. Когда мы перебираем список хэшей и хотим отобразить hash.created,, мы сталкиваемся с неудобными ошибками. С помощью описанных правил проверки мы защищаем себя от ошибок такого типа.
Получение и хранение данных
Сейчас мы хотим создать магазин, который подписывается на хэши пользователей и предоставляет действия для добавления новых данных.
Мы получаем экземпляр хранилища аутентификации и начинаем подписываться на данные через on('child_added')listener, который сначала извлекает все данные, а затем только вновь добавленные данные. Звучит хорошо, не правда ли?
… вроде, как бы, что-то вроде :)
Эта реализация будет очень подвержена ошибкам, поскольку this.authStore.user может быть неопределенным - и start() вообще не сможет запустить подписку.
Какая удача, что у этого mobx есть замечательная функция под названием autorun для обработки этого конкретного случая ❤!
Автозапуск срабатывает, как только наблюдаемые this.authStore.user изменения изменятся, и завершит работу, как только this.authStore.user станет действительным. Как это круто?!
Редактировать: Мишель Вестстрат указал, что на самом деле предоставляет функцию именно для этого случая - autorun один раз и dispose() сам, о чем я не знал: https: // mobx .js.org / refguide / when.html
С when мы можем переписать наш приведенный выше код следующим образом:
Использование и добавление данных
Теперь у нас есть вся логика нашего хранилища, давайте найдем место для инициализации хранилища и слушателей, запустив start().
Итак, здесь у нас есть поле ввода, которое запускает действие сохранения onChange. Это не совсем оптимально, поскольку каждый onChange создает одну запись в базе данных, но мы будем придерживаться этого для простоты - , если вы хотите знать как я решил это в приложении, проверьте репозиторий, прикрепленный внизу. Кроме того, в настоящее время мы проверяем только child_added событий. Мы не заметим изменения или удаления событий. Еще один недостаток нашей текущей реализации заключается в том, что мы не знаем, пуст наш магазин или просто еще не загружен.
Firebase предоставляет несколько слушателей для решения этих проблем. С ref.once('value') мы можем получить полную ссылку один раз. Эта функция особенно полезна, чтобы различать загруженное и пустое состояния, поскольку мы можем установить переменную состояния, например. @observable ready, который установлен в разрешении обещания. Всякий раз, когда переменная true,, мы знаем, что исходные данные загружены (даже если они пусты). child_changed и child_removed работают аналогично child_added обещание преобразуется в объект данных, содержащий обновленную / удаленную запись. Теперь мы можем использовать ответ на обещание для обновления нашего магазина mobx.
Я вложил много ❤ и усилий в эту статью, и я рад повторить / исправить / обновить ее :) Если у вас есть какие-либо отзывы, дайте мне знать в комментариях! Кроме того, если у вас есть предложения по темам для дальнейших статей, напишите мне сообщение.
Как всегда, вы можете найти текущую версию кода через тег v0.0.3 на github.