JS: REST API (Fastify)
Теория: Интеграция с базой данных
Технически, мы бы могли изучить работу REST API без использования баз данных, сохраняя данные в памяти. Но в таком случае, понимание устройства таких сервисов было бы не полным. Поэтому для полноценного погружения понадобится взаимодействие с базой данных.
В Node.js с этим есть определенные сложности из-за разрозненности комьюнити. Есть десятки решений для работы с базой, начиная от простых драйверов, заканчивая навороченными ORM, среди которых нет одного явного лидера. Часть этих решений заточено под TS, часть под JS, но устарело, что-то является полноценным ORM, что-то нет. Некоторые даже вводят свои языки описания.
Из-за этого не так просто выбрать решение, которое бы подошло всем. На текущий момент, пожалуй, самыми перспективным является проект Drizzle. Именно его мы и будем использовать. В рамках этого урока мы выполним две задачи:
- Подключим его к проекту и настроим работу с ним.
- Научимся им пользоваться.
Drizzle хотя и называется ORM, фактически это продвинутый билдер запросов (query builder), который отлично работает и в JavaScript и в TypeScript. Drizzle поддерживает множество разных баз данных, предоставляя единообразный (почти) интерфейс для работы с ними. Поэтому для простоты, в этом курсе мы будем использовать базу данных sqlite в памяти. В таком случае нам не придется поднимать базу данных отдельно и заниматься ее поддержкой и очисткой. Особенно это удобно для тестов.
Установка и подключение к Fastify
Для начала установим нужные пакеты:
Затем создадим конфигурационный файл drizzle.config.js:
Подключение Drizzle к Fastify делается через плагины. Добавьте файл plugins/drizzle.js с таким содержимым:
В этом коде выполняется подключение к базе данных, ее подготовка и добавление объекта db в Fastify. Через этот объект, мы будем взаимодействовать с базой данных внутри обработчиков запросов, например:
Что входит в подготовку базы данных?
Применение миграций
Миграции, это файлы с sql-кодом, которые меняют схему базы данных приводя ее в нужное состояние. Миграции это способ, которым база данных изменяется со временем.

В Drizzle используется Code First подход. То есть схема данных описывается в коде, на основе которого генерируются миграции и, затем, применяются к базе данных.
Обычно, миграции применяются через явно вызываемую команду из командной строки. В нашем случае можно проще, так как мы работаем с базой данных в памяти, она будет уничтожена после остановки приложения.
Загрузка начальных данных
Для простоты, базу данных можно сразу заполнить данными упростив работу во время разработки и тестирования. Такие данные обычно называют сидами. Опять же, из-за работы с базой в памяти, мы можем грузить сиды при старте Fastify, так как после остановки база данных пропадает.
Создание структуры
Для работы с Drizzle нам нужно выполнить следующие шаги:
- Описать схему базы данных.
- Сгенерировать миграции на базе схемы.
- Описать сиды для заполнения базы данных.
Схема данных
В этом курсе мы будем работать с моделью данных описывающей пользователей, курсы и уроки, где мы можем создавать пользователей, пользователи могут создавать курсы с уроками и просматривать их.
Создайте файл db/schema.js со следующим содержимым:
Каждая константа описывает таблицу в базе. В описании задается имя таблицы, название полей в JS (ключи) и название полей в базе (значение). Для базы задается тип поля и если нужно, ограничения.
Когда структура описана, мы можем создать миграцию:
Эта команда создает директорию drizzle, в которой хранятся служебные файлы и файлы миграций. Директорию нужно добавить в git, но работать с ней напрямую мы не будем. Если что-то пойдет не так, в нашем случае, ее можно удалить сгенерировать заново.
И последние, создание сидов. Заполните файл db/seeds.js таким содержимым:
Здесь мы видим код использования Drizzle. Принципы работы с базой через Drizzle мы рассмотрим чуть позже, а сейчас добавим еще один файл, нужный для работы с сидами. Это файл с функциями генерирующими данные для табличек. Они нужны для устранения дублирования, когда мы начнем писать тесты и нам понадобится создавать сущности. Создайте файл lib/data.js и скопируйте туда код ниже:
Здесь мы используем faker, для генерации нужных данных с возможностью их переопределить через параметры функции. Эти функции используются в сидах и будут использоваться в тестах.
Работа с Drizzle
Drizzle пытается быть максимально близким к SQL. Запросы написанные с его помощью, работают именно так как написано, в отличие от ORM, в которых запросы часто скрыты за высокоуровневыми командами. У такого подхода есть и плюсы и минусы. Плюс в том, что нет никакой магии и для работы с Drizzle достаточно знать SQL, минус же, связан с необходимостью писать больше кода чем в классических ORM, которые автоматизируют многие задачи.
Соберем все вместе и посмотрим на то как выполняются запросы с помощью Drizzle.
Выборки
Для начала изучим выборку данных.
В этом коде выбираются пользователи отсортированные в порядке возрастания id. Что можно сказать глядя на код:
- Запросы к базе выполняются асинхронно.
db.query.users- последний объект появляется внутри благодаря тому, что функцияdrizzle()создает объектdbна базе переданных схем таблиц.findMany()возвращает коллекцию объектов, где каждый объект содержит поля соответствующие ключам в схеме (id,fullName,emailи т.п.)- Условия, сортировка и другие манипуляции с данными делаются с помощью объекта переданного в
findMany(). Все параметры внутри него не обязательны
Самое интересное тут это язык описания используемый в сортировке. Он использует метод asc() для указания способа сортировки, в который передается поле из схемы. Последнее содержит метаинформацию о поле, а не конкретное значение.
Очень похоже выглядит фильтрация:
В примере выше извлекаются все пользователи с именем Jonny Depp. Если нам нужен один пользователь, то мы можем задать лимит:
Либо воспользоваться методом findFirst():
Во всех этих случаях возможна ситуация, когда записей в базе нет. Это не приводит к ошибке, как и в случае с прямой работой с SQL.
Изменение данных
Создание, обновление и удаление данных выглядят очень похоже, поэтому рассмотрим их все вместе.
Все три запроса имеют общие элементы. В каждый из них передается схема, с которой идет работа, в данном случае users. Каждый запрос ничего не возвращает, если не добавлен метод returning(). Когда он добавлен, то возвращаются те строки, которые были затронуты запросом. И это всегда массив, даже если была затронута одна запись, поэтому во всех примерах используется деструктуризация.
Рекомендуемые программы
Завершено
0 / 15
