Привет, друзья! В этом цикле из 2 статей я хочу рассказать вам о Supabase — открытой (open source), т.е. бесплатной альтернативе Firebase. Первая статья будет посвящена теории, во второй — мы вместе с вами разработаем полноценное social app с аутентификацией, базой данных, хранилищем файлов и обработкой изменения данных в режиме реального времени. Что такое Supabase? Supabase, как и Firebase — это SaaS (software as a service — программное обеспечение как услуга) или BaaS (backend as a service — бэкенд как услуга). Что это означает? Это означает, что при разработке fullstack app мы разрабатываем только клиентскую часть, а все остальное предоставляется Supabase через пользовательские комплекты для разработки программного обеспечения (SDK) и интерфейсы прикладного программирования (API). Под "всем остальным" подразумевается сервис аутентификации (включая возможность использования сторонних провайдеров), база данных (PostgreSQL), файловое хранилище, realtime (реакцию на изменение данных в реальном времени), и сервер, который все это обслуживает. Если вам это интересно, прошу под кат. Лаконичность дальнейшего изложения обусловлена желанием уместить всю (ну почти) необходимую информацию в одной статье. Поехали! Установка Импорт Инициализация По умолчанию для выполнения HTTP-запросов supabase-js использует библиотеку cross-fetch. Это можно изменить следующим образом: Регистрация Для регистрации нового пользователя используется метод signUp: Такая сигнатура позволяет вызывать данный метод следующим образом (на примере React-приложения): В TypeScript можно использовать такую сигнатуру: Обратите внимание: по умолчанию после регистрации пользователь должен подтвердить свой email. Это можно отключить в разделе Authentication -> Settings. Авторизация Для авторизации, в том числе с помощью сторонних провайдеров, используется метод signIn: Если авторизация выполняется только через email, пользователю отправляется так называемая магическая ссылка/magic link. Пример авторизации с помощью аккаунта GitHub: Выход из системы Для выхода из системы используется метод signOut: Для того, чтобы сообщить серверу о необходимости завершения сессии используется метод auth.api.signOut(jwt). Сессия Метод session используется для получения данных активной сессии:  Метод user возвращает данные авторизованного пользователя: В данном случае возвращается объект из локального хранилища. Для получения данных пользователя из БД используется метод auth.api.getUser(jwt). На стороне сервера для этого используется метод auth.api.getUserByCookie. Обновление данных пользователя Для обновления данных пользователя используется метод update: Регистрация изменения состояния авторизации Сброс пароля После вызова этого метода на email пользователя отправляется ссылка для сброса пароля. Когда пользователь кликает по ссылке, он переходит по адресу: SITE_URL/#access_token=X&refresh_token=Y&expires_in=Z&token_type=bearer&type=recovery. Мы регистрируем type=recovery и отображаем форму для сброса пароля. Затем используем access_token из URL и новый пароль для обновления пользовательских данных: Извлечение (выборка) данных Сигнатура: Пример: По умолчанию максимальное количество возвращаемых строк равняется 1000. Это можно изменить в настройках. select() может использоваться совместно с модификаторами и фильтрами (будут рассмотрены позже). Получение данных из связанных таблиц Фильтрация данных с помощью внутреннего соединения (inner join) Предположим, что мы хотим извлечь сообщения (messages), принадлежащие пользователю с определенным именем (username): Получение количества строк Получение данных из JSONB-столбцов Получение данных в формате CSV Запись (добавление, вставка) данных Сигнатура: Пример: Разумеется, можно создавать несколько записей одновременно: Обратите внимание: для обновления строк с помощью upsert: true данные должны содержать первичные или основные ключи/primary keys соответствующей таблицы. Модификация данных Сигнатура: Пример: Обратите внимание: метод update должен всегда использоваться совместно с фильтрами. Пример обновления JSON-колонки В настоящее время поддерживается обновление только объекта целиком. Модификация или запись данных Сигнатура: Пример: Разумеется, можно обновлять или создавать несколько записей за раз. Обратите внимание на 2 вещи: Удаление данных Сигнатура: Пример: Вызов функций Postgres Сигнатура: Предположим, что мы определили такую функцию: Данную функцию можно вызвать следующим образом: Метод rpc может использоваться совместно с модификаторами и фильтрами, например: Модификаторы используются в запросах на выборку данных (select). Они также могут использоваться совместно с методом rpc, когда он возвращает таблицу. limit() Модификатор limit ограничивает количество возвращаемых строк. Сигнатура: Пример: Пример с внешней таблицей: order() Модификатор order сортирует строки в указанном порядке. Сигнатура: Пример: range() Модификатор range возвращает диапазон строк (включительно). Сигнатура: Пример: single() Модификатор single возвращает одну строку. Пример: Существует также модификатор maybeSingle, возвращающий хотя бы одну строку. Фильтры могут использоваться в запросах select, update и delete, а также в методе rpc, когда функция возвращает таблицу. Фильтры должны применяться в конце запроса. Их можно объединять в цепочки и применять условно. Примеры: Виды фильтров: Настройки также принимают второй параметр type, возможными значениями которого являются plain и phrase, определяющие базовую и полную нормализацию, соответственно. Также имеется несколько других (более специфичных) фильтров. Для создания файлового хранилища используется метод createBucket: Для создания хранилища требуются следующие разрешения (permissions policy): В Supabase безопасность работы с данными и файлами обеспечивается установкой и настройкой row level security (политик защиты строк). Мы рассмотрим их в следующей статье. Для получения данных о хранилище используется метод getBucket: Требуются следующие разрешения: Для получения списка хранилищ используется метод listBuckets: Требуются аналогичные разрешения. Для обновления хранилища используется метод updateBucket(id, options) (разрешение buckets: update), а для удаления — метод deleteBucket(id) (buckets: select и delete). Обратите внимание: непустое хранилище не может быть удалено без его предварительной очистки с помощью метода emptyBucket(id) (buckets: select, objects: select и delete). Загрузка файлов Для загрузки файлов в хранилище используется метод upload. Сигнатура Разрешения: Пример Скачивание файлов Для скачивания файлов используется метод download: Разрешения: Получение списка файлов Для получения списка файлов используется метод list. Сигнатура Пример Разрешения: Обновление файлов Для обновления файлов используется метод update. Сигнатура Пример Разрешения: Для перемещения файла с его опциональным переименованием используется метод move: Разрешения: Удаление файлов Для удаления файлов используется метод remove: Разрешения: Формирование пути к файлу Для формирования пути к файлу без разрешения используется метод createSignedUrl: Разрешения: Для формирования пути к файлу, находящемуся в публичной директории, используется метод getPublicUrl: Разрешения не требуются. Подписка на изменения Для подписки на изменения, происходящие в БД, используется метод subscribe в сочетании с методом on. Сигнатура Обратите внимание: Примеры Регистрация всех изменений всех таблиц: Регистрация изменений определенной таблицы: Регистрация записи данных в определенную таблицу: Обработчики можно объединять в цепочки: Имеется возможность регистрации изменений определенных строк. Синтаксис: Отписка от изменений Метод removeSubscription удаляет активную подписку и возвращает количество открытых соединений. Для удаления всех подписок и закрытия WebSocket-соединения используется метод removeAllSubscriptions. Получение списка подписок Для получения списка подписок используется метод getSubscriptions. Пожалуй, это все, чем я хотел поделиться с вами в данной статье. Благодарю за внимание и happy coding!  JavaScript Developer