Масштабируемый бэкенд на Node.js: AWS Lambda, Neon и Drizzle

freeCodeCamp.org 103 тыс. 4 ч 4 мин 27 мин 28.02.2024
Главное

«Serverless — это по сути просто фокус на коде: вы его деплоите, а масштабирование под нагрузку берет на себя кто-то другой», — утверждает Джастин Митчелл. В этом руководстве мы разберем создание масштабируемого API на стеке AWS Lambda, Neon Postgres и Drizzle ORM, превращая управление инфраструктурой в автоматизированный процесс, где секреты не покидают облако, а базы данных разворачиваются по требованию.

🚀 Основы Serverless: фокус на коде, а не на инфраструктуре 0:25

Переход к разработке в serverless-среде фундаментально меняет подход к созданию приложений: основное внимание смещается исключительно на написание кода, избавляя разработчика от необходимости управлять серверами. Традиционные серверные приложения требуют постоянной работы: они запущены 24/7, что влечет за собой фиксированные расходы на инфраструктуру, даже когда ими никто не пользуется.

Аналогия с освещением в комнате лучше всего иллюстрирует разницу:

Масштабирование в классической архитектуре требует ручного управления: если на ваш сайт внезапно заходит тысяча человек вместо одного, стандартного «настольного» сервера не хватит. Вам придется настраивать балансировщики нагрузки, добавлять новые экземпляры и следить за состоянием системы. В модели serverless, такой как AWS Lambda, это происходит автоматически: платформа сама масштабирует исполнение кода в ответ на поток запросов.

AWS Lambda стала пионером этого направления, предлагая невероятно щедрый бесплатный уровень — до 1 миллиона запросов в месяц без какой-либо оплаты. Однако прямая работа с облачными провайдерами может быть сложной из-за обилия настроек. Именно здесь на помощь приходят инструменты оркестрации, такие как Serverless Framework, которые позволяют автоматизировать деплой и управление инфраструктурой через компактные конфигурационные файлы.

🛠 Настройка окружения с Serverless Framework 12:25

Для эффективной разработки приложений, предназначенных для AWS Lambda, критически важно иметь возможность тестировать код локально, эмулируя «облачное» поведение. Serverless Framework является стандартом де-факто для этой задачи.

Первым шагом после установки фреймворка является инициализация проекта. Использование шаблона для Express API позволяет быстро развернуть базовую структуру приложения, совместимую с serverless-архитектурой. Важный нюанс: при локальной разработке мы отходим от классического метода запуска сервера через app.listen(), который «держит» процесс активным постоянно, и переходим к экспорту обработчика (handler), который запускается только по вызову.

Для эмуляции поведения AWS Lambda на локальной машине используется плагин serverless-offline:

Для удобства рекомендуется добавить команду запуска в секцию scripts файла package.json:

"scripts": {
  "dev": "serverless offline --stage dev"
}

Это упрощает процесс разработки до одной команды npm run dev. Также важно следить за конфигурационным файлом serverless.yaml, где задается рантайм среды. Необходимо убедиться, что версия Node.js (например, 20.x) совпадает как в локальном окружении, так и в настройках AWS Lambda, что обеспечивает целостность разработки и продакшена. В вопросах интеграции баз данных ранее в разговоре затрагивались преимущества Neon, который дополняет этот стек, предоставляя serverless-базы данных, работающие в тандеме с AWS Lambda.

🛠️ Порядок в коде и магия ветвления: Оптимизация рабочего процесса 25:06

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

Рефакторинг структуры: переход к директории /src 25:20

Первым делом в процессе разработки принимается решение об изоляции программного кода от конфигурации проекта. Хотя изначально файл index.js находился в корне, по мере усложнения приложения это становится неудобным. Создание отдельной папки src/ позволяет четко разделить «инфраструктурный шум» и саму логику приложения.

Однако простой перенос файла требует синхронизации с конфигурацией Serverless Framework. В файле serverless.yml необходимо обновить путь к обработчику (handler). Теперь он выглядит как src/index.handler. Важно помнить, что при настройке путей интуиция (например, использование точечной нотации) может подвести, поэтому проверять работоспособность через локальный запуск стоит на каждом этапе.

Такой подход позволяет использовать serverless-offline для разработки, при этом обработчик корректно находит точку входа в подпапке. Интересно, что благодаря механизму экспорта в Node.js, приложение может поддерживать как традиционный запуск через app.listen, так и специфичный для AWS Lambda формат экспорта функций, не создавая конфликтов в пространстве имен.

Экосистема плагинов: Serverless Offline и Dotenv 28:40

Для полноценной работы локального окружения недостаточно просто запустить код — нужно научить его взаимодействовать с переменными окружения так, как это будет происходить в облаке. Ранее в курсе затрагивалась общая концепция .env файлов, но здесь акцент делается на специфике AWS Lambda.

Вместо стандартного пакета dotenv, который часто используется в Node.js приложениях, для Serverless-проектов рекомендуется плагин serverless-dotenv-plugin. Его преимущество в том, что он обеспечивает более глубокую интеграцию с жизненным циклом фреймворка и корректно пробрасывает переменные в Lambda-функции. Процесс установки прост:

Это подготавливает почву для работы с чувствительными данными, подробный разбор которых (включая безопасность и .env) запланирован в главе 3. Важным нюансом локальной отладки является поведение типов данных: переменные окружения всегда приходят в коде как строки, даже если в файле они выглядят как числа. Например, проверка debug === 1 может вернуть false, если не обернуть единицу в кавычки или не привести тип явно.

Ветвление базы данных: новый стандарт разработки в Neon 35:22

Одной из самых инновационных функций Neon Serverless Postgres является механизм ветвления (branching). Это концепция «снимков» (snapshots) базы данных в определенный момент времени, которые можно мгновенно превратить в изолированные копии для разработки или тестирования.

При создании нового проекта в консоли Neon важно уделить внимание выбору региона. Рекомендуется выбирать локацию, максимально близкую к вашему AWS-региону (например, us-east-2 в Огайо), чтобы минимизировать задержки. После создания проекта Neon сразу предоставляет строку подключения, которую мы будем использовать для интеграции в следующей главе.

Магия ветвления раскрывается, когда вам нужно протестировать миграции или новые фичи, не затрагивая «мастер»-данные:

Это позволяет реализовать пайплайны, где каждая ветка в Git имеет свою собственную копию базы данных. Более того, базы данных в Neon умеют «засыпать» (scale to zero), когда к ним нет обращений, и мгновенно «просыпаться» при поступлении запроса, что идеально ложится в философию Serverless.

Подготовка Neon CLI к работе 44:06

Хотя интерфейс консоли удобен, для настоящей автоматизации необходим CLI-инструмент. Утилита neonctl позволяет управлять проектами и ветками прямо из терминала. Процесс подготовки включает несколько шагов:

  1. Глобальная установка: npm install -g neonctl.
  2. Авторизация: команда neonctl auth открывает браузер для подтверждения доступа.
  3. Опциональная установка jq: эта утилита крайне полезна для парсинга JSON-ответов от CLI при автоматизации скриптов.

Работа с проектами через CLI строится по логике, схожей с Kubernetes: вы указываете ресурс (например, projects или branches) и действие (list, create, delete). Это позволяет, например, создать новый проект одной командой neonctl projects create --name "serverless-api" и сразу получить строку подключения. При этом нужно быть осторожным: CLI позволяет удалять проекты так же легко, как и создавать их, что требует внимательности при работе с идентификаторами.

🔌 Интеграция базы данных и управление конфигурацией среды 50:32

Мгновенное ветвление и возможности масштабирования Neon 51:37

Neon Serverless Postgres предоставляет разработчикам мощный инструмент для автоматизации и тестирования — мгновенное создание веток (branching) данных. Это позволяет под каждую ветку кода или стадию разработки разворачивать изолированную копию базы данных со своей уникальной строкой подключения. На бесплатном тарифе Neon действует ограничение на создание только одного проекта, однако внутри этого единственного проекта можно создавать множество веток, а внутри каждой ветки — несколько независимых баз данных. Такой подход идеально подходит для организации процессов стейджинга и автоматизации деплоя, позволяя безболезненно удалять ненужные ресурсы, как только необходимость в них отпадает. Ранее в разговоре авторы уже затрагивали основы настройки окружения с Serverless Framework, которые легли в основу текущей архитектуры проекта.

Подключение Neon Serverless Postgres к Node.js 53:34

Для интеграции базы данных в приложение Node.js критически важно использовать специализированный пакет @neondatabase/serverless, а не классический драйвер вроде node-postgres (pg). Причина кроется в специфике serverless-архитектуры: традиционный пулинг соединений плохо работает в условиях, когда серверные инстансы постоянно масштабируются до нуля и создаются заново. Вместо этого Neon использует эффективные HTTP-соединения. Для оптимизации работы в развернутой среде рекомендуется включать экспериментальную опцию fetchConnectionCache: true, которая кэширует HTTP-подключения и снижает накладные расходы на установку связи.

При переносе кода интеграции в файл index.js разработчики могут столкнуться с архитектурным нюансом: по умолчанию в Express-приложениях используется среда CommonJS, из-за чего стандартный синтаксис import вызовет ошибку «cannot use an import statement outside a module». Решением становится использование классического require() для подключения клиента SQL. Кроме того, выполнение запросов к БД требует перевода обработчиков маршрутов Express в асинхронный режим с использованием ключевых слов async/await. Первый запрос к базе данных может потребовать некоторого времени (холодный старт), так как инстанс Neon в консоли должен активироваться после простоя. Однако последующие запросы выполняются молниеносно, даже если база данных физически расположена на другом конце страны в регионе US East. Результаты сырых SQL-запросов (SELECT NOW()) возвращаются в виде массива, из которого легко извлечь актуальную временную метку.

Безопасное управление переменными окружения через .env файлы 1:02:50

Управление секретами и строками подключения на разных стадиях проекта реализуется через файлы конфигурации среды. Для локальной разработки используется файл .env.dev (соответствующий стадии dev в Serverless Framework), куда помещается целевой DATABASE_URL. При подготовке к первому промышленному развертыванию в package.json добавляется скрипт деплоя с явным указанием стадии prod. Использование скриптов автоматизации избавляет разработчика от необходимости каждый раз вручную вводить специфические флаги сборки в консоли.

В процессе локальной сборки Serverless Framework считывает переменные из соответствующего .env-файла текущей стадии и упаковывает весь код репозитория в zip-архив внутри директории .serverless. При этом файлы .env и директория .git исключаются из архива, что предотвращает их случайную отправку в облако. Однако детальный анализ локального файла состояния (state file) выявляет серьезную проблему безопасности: конфиденциальная строка DATABASE_URL записывается туда в открытом виде. В дальнейших главах будет подробно рассмотрено безопасное хранение секретов в AWS SSM для устранения этой уязвимости. Также для минимизации сетевых задержек критически важно сопоставлять регион деплоя AWS Lambda с регионом базы данных. Проверить текущий регион проекта Neon (например, us-east-2) можно с помощью утилиты командной строки Neon CLI.

Конфигурация локальных AWS-доступов для деплоя 1:07:03

Для выполнения команд деплоя локальная машина должна обладать необходимыми правами доступа к AWS. Вместо использования глобальных системных учетных данных (~/.aws/credentials), которые могут конфликтовать с другими проектами на компьютере, рекомендуется передавать ключи AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY изолированно через файл .env конкретного проекта.

Для этого в консоли AWS IAM создается выделенная группа пользователей (например, serverless-framework) и сервисный пользователь с ограниченными правами, привязанный к конкретному API-проекту. Полномочия этого пользователя строго ограничиваются кастомной политикой разрешений из JSON-шаблона, где глобальный идентификатор заменяется на реальный AWS ID аккаунта разработчика. Подобное сужение прав крайне важно: выдача избыточного административного доступа (AdministratorAccess) чревата случайным развертыванием лишних дорогостоящих сервисов или компрометацией ключей. Настройка IAM-политик для Serverless подробно рассматривается в главе 6, а на данном этапе кастомная политика применяется как готовый инструмент из репозитория проекта для обеспечения базового деплоя.

🛠️ Автоматизация инфраструктуры Neon через CLI 1:24:22

Управление строками подключения и авторизация 1:24:22

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

Основная задача утилиты на этом этапе заключается в предоставлении точной и актуальной строки подключения для базы данных без лишних манипуляций в браузере. Разработчик извлекает этот параметр прямо в терминале, чтобы оперативно интегрировать его в систему управления конфигурациями проекта. Ранее в руководстве рассматривались базовые принципы работы с локальными переменными окружения (.env), однако прямая передача таких секретов в открытом виде внутри конфигурационных файлов или JSON-стейтов деплоя несет огромные риски безопасности. Программный вызов через CLI нивелирует эти угрозы, позволяя динамически запрашивать доступы. Полученный URL-адрес содержит зашифрованные учетные данные, хост и имя целевой базы, гарантируя моментальное и безопасное соединение с облачной СУБД Postgres.

Программное создание баз данных и управление ветвлением 1:24:22

Уникальной особенностью Neon Serverless Postgres является встроенная поддержка Git-подобного ветвления (branching) данных, которой можно полноценно управлять через интерфейс командной строки. Разработчики могут мгновенно создавать изолированные слепки основной базы для безопасного тестирования новых функций. Это полностью избавляет команду от необходимости разворачивать громоздкие локальные базы данных или вручную синхронизировать схемы таблиц между участниками проекта. В гибком serverless-окружении, где облачные функции создаются и уничтожаются по первому требованию, возможность столь же оперативно разворачивать новые изолированные инстансы баз данных становится весомым преимуществом.

Инструментарий CLI предоставляет инженерам обширный набор возможностей для бесшовного управления жизненным циклом данных:

Команда создания новой ветки позволяет эффективно разграничить окружения. Например, для стадии prod задействуется стабильная корневая ветка СУБД, в то время как локальная отладка через npm run dev переводится на выделенную dev-ветку. Управление адресами подключения для каждого инстанса полностью автоматизировано командами CLI. Благодаря этому сама база данных выносится за рамки управления конфигурацией серверлесс-фреймворка, что предотвращает непреднамеренное удаление или модификацию ценной информации при обновлении серверной части приложения.

Интеграция CLI в рабочий процесс и обработка ошибок 1:24:22

Прямая интеграция Neon CLI в пайплайны автоматизации открывает огромные перспективы для генерации динамических тестовых сред под каждый отдельный пулл-реквест. Утилита поддерживает вывод данных в структурированном формате JSON, что упрощает автоматический парсинг строк подключения и их последующую передачу в сопутствующие облачные сервисы. В описываемом рабочем процессе полученная строка подключения сохраняется в зашифрованном виде на стороне провайдера, защищая архитектуру от утечек через открытые логи или файлы конфигурации, из которых чувствительные переменные принудительно удаляются перед деплоем.

Однако глубокая автоматизация требует пристального внимания к правам доступа и механизмам обработки исключений. Ошибки при указании параметров в CLI или опечатки в идентификаторах проекта неизбежно приведут к сбоям — приложение выдаст внутреннюю ошибку при попытке первого обращения к клиенту базы данных. Ранее в обсуждении затрагивались смежные вопросы настройки IAM-политик для Serverless, а также безопасное хранение секретов в AWS SSM, детальный разбор которых запланирован в шестой главе. Если в режиме локальной разработки статус подключения проверяется мгновенно прямо в окне браузера, то в условиях реального продакшена для поиска причин отказов разработчикам необходимо анализировать логи CloudWatch. Использование CLI как единого автоматизированного инструмента для управления Neon сводит вероятность конфигурационных ошибок к минимуму, превращая работу с базами данных в предсказуемый и безопасный процесс.

🛠 Оптимизация и декомпозиция серверной логики 143:45

Для создания масштабируемого приложения важно поддерживать чистоту кодовой базы. Основная работа на данном этапе сосредоточена на декомпозиции приложения и переходе на современные инструменты AWS SDK.

Обновление AWS SDK и декомпозиция секретов 143:57

Для улучшения модульности и уменьшения размера пакета было решено отказаться от использования устаревшего aws-sdk в пользу более современного пакета aws-sdk/client-ssm. Процесс декомпозиции включал в себя создание отдельного модуля lib/secrets.js, который берет на себя ответственность за извлечение секретов из AWS Systems Manager (SSM).

Этот шаг позволил удалить лишние зависимости (такие как Express.js) из модуля получения конфигурации базы данных. Теперь процесс получения databaseUrl стал асинхронным и изолированным, что значительно упрощает дальнейшую поддержку проекта.

Реорганизация клиента базы данных 147:43

Следуя принципу разделения ответственности, мы выделили инициализацию клиента базы данных в отдельный файл db/client.js. Ранее в index.js содержалось множество конфигурационных деталей, которые загромождали основной код. После рефакторинга импорт клиента стал лаконичным:

const getDbClient = require('./db/client');
const sql = await getDbClient();

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

🏗 Проектирование схем данных через Drizzle ORM 153:12

Переход к использованию Drizzle ORM позволяет управлять структурой базы данных непосредственно через JavaScript, избегая написания чистого SQL-кода при каждом изменении. ORM берет на себя типизацию, что критически важно: данные из базы (например, метки времени) приходят как готовые JavaScript-объекты, избавляя от необходимости ручного парсинга [154:3].

Определение структуры таблицы 154:28

Для проекта была спроектирована таблица leads. При выборе типов данных мы опирались на функциональные возможности Postgres:

Автоматизация миграций 202:40

Для синхронизации описанной схемы с реальной базой данных был настроен файл drizzle.config.js [203:7]. Это позволило автоматизировать процесс генерации SQL-файлов миграций через команду npm run generate.

Теперь, при любом изменении схемы — будь то добавление колонок или создание новых таблиц — достаточно выполнить генерацию, чтобы получить актуальный SQL-код, готовый к применению в базе данных. Ранее в разговоре они касались работы с переменными окружения и первичной настройки инфраструктуры, но использование ORM-миграций делает этот процесс куда более прозрачным и безопасным.

🔐 Безопасность и управление инфраструктурой в Serverless 2:05:51

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

Безопасное хранение секретов в AWS SSM 2:08:42

Использование AWS Systems Manager (SSM) Parameter Store позволяет перенести управление конфигурациями на уровень облачной инфраструктуры. Вместо того чтобы хранить DATABASE_URL или ключи доступа в обычных файлах, мы делегируем их хранение специализированному сервису, который обеспечивает шифрование данных.

В контексте нашего CLI-инструмента для миграций, работа с секретами требует правильной настройки загрузки переменных окружения. Использование библиотеки dotenv в связке с process.env позволяет динамически подтягивать нужные значения. Например, при создании модуля migrator.js мы импортируем секреты через отдельный сервис, который безопасно извлекает актуальный URL базы данных.

Это дает несколько преимуществ:

Настройка IAM-политик для Serverless 2:07:22

Когда мы автоматизируем работу с инфраструктурой через собственный CLI-инструмент (в нашем случае для взаимодействия с Neon Postgres), необходимо уделить внимание правам доступа. Создание минимально необходимых IAM-политик — залог того, что фреймворк или скрипт миграции не получит избыточных полномочий.

Ранее в разговоре обсуждались основы Serverless-архитектуры и настройка окружения через Serverless Framework, что является фундаментом для применения данных политик. При настройке прав для нашего «мигратора», роль, под которой выполняется скрипт, должна иметь строго ограниченный набор разрешений. Это гарантирует, что даже в случае компрометации скрипта, злоумышленник не сможет получить доступ ко всей инфраструктуре AWS, а только к конкретным параметрам в SSM, необходимым для выполнения миграций.

При разработке подобных инструментов важно следовать принципу наименьших привилегий:

🛠️ Шлифовка CRUD и автоматизация окружений 2:30:40

Логика обработки ответов и расширенные запросы Drizzle 2:30:52

После того как базовая интеграция базы данных настроена, работа переходит в плоскость чистого программирования логики API. Одной из особенностей работы с Drizzle ORM при вставке данных является формат возвращаемого результата: библиотека возвращает не один объект, а массив. Это логично для SQL, но требует дополнительной обработки в коде Express.

Чтобы сделать API удобным для фронтенда, автор внедряет проверку: если длина массива результатов равна единице, функция возвращает только первый элемент result[0], в противном случае — весь список или null. Это позволяет сразу получать чистый объект с данными, включая автоматически инкрементируемый ID и таймштампы, созданные на стороне сервера.

Развитие CRUD-функционала (Create, Read, Update, Delete) продолжается реализацией списка лидов:

Автор подчеркивает, что Drizzle позволяет писать SQL-подобный код на чистом JavaScript, что избавляет от необходимости составлять сырые SQL-запросы вручную, сохраняя при этом полный контроль над структурой.

Архитектура валидации: создание слоя безопасности 2:39:24

Критически важный этап разработки любого API — это очистка и проверка входящих данных. Автор решает вынести эту логику в отдельный модуль validators.js, чтобы не загромождать основной код сервера. Основная идея здесь заключается в том, что база данных должна получать только гарантированно корректную информацию.

В основе системы валидации лежит библиотека Zod, которая позволяет описывать схемы объектов и автоматически проверять их соответствие. В данном проекте основное внимание уделяется проверке email-адресов. Используя метод z.string().email(), разработчик может в несколько строк кода убедиться, что входящая строка является валидным почтовым адресом.

Логика функции validateLead строится на следующих принципах:

  1. Блок Try-Catch: Попытка парсинга данных через lead.parse(postData). Если данные неверны, Zod выбрасывает ошибку, которую перехватывает блок catch.
  2. Управление статусами ответов:
    • 201 Created: Если данные валидны и успешно вставлены.
    • 400 Bad Request: Если валидация не прошла (например, неверный формат email).
    • 500 Server Error: Если произошла непредвиденная ошибка на стороне сервера.

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

Эфемерные базы и автоматизация параметров AWS 2:51:04

Когда CRUD-логика и валидация готовы, встает вопрос масштабирования разработки. Автор переходит к автоматизации процесса развертывания сред (Staging). Идея заключается в том, чтобы при создании новой ветки кода в GitHub автоматически создавалась и соответствующая инфраструктура.

Ключевым инструментом здесь выступает Neon CLI, который позволяет создавать «ветки» (branches) базы данных. Это делает базы данных эфемерными: разработчик может создать ветку dev, поработать с ней и удалить в любой момент, не затрагивая основные данные. Команда neonctl connection-string dev мгновенно выдает URL для подключения к этой изолированной среде.

Однако наличие нового URL базы данных требует его обновления в облачном хранилище секретов. Ранее для хранения секретов использовался AWS SSM (Parameter Store), но данные вносились туда вручную. Для автоматизации этого процесса автор пишет функцию putDatabaseUrl, использующую AWS SDK.

В этой логике заложен важный предохранитель: функция проверяет текущую стадию (stage). Если это prod, автоматическое обновление блокируется. Продакшн-параметры должны меняться только вручную, чтобы избежать случайной перезаписи критических данных при автоматическом деплое. Таким образом, автоматизация ускоряет разработку, сохраняя при этом безопасность основного окружения.

🛠️ Управление базой данных: от схем Drizzle ORM до автоматических миграций 2:57:47

Проектирование схем базы данных с помощью Drizzle ORM 2:57:47

Использование объектно-реляционного отображения (ORM) в современных бессерверных архитектурах стало индустриальным стандартом, и Drizzle ORM занимает в этом процессе ключевое место. Вместо традиционного и зачастую сопряженного с ошибками ручного написания SQL-запросов для создания таблиц, Drizzle предлагает строго декларативный подход. Структура базы данных описывается непосредственно на JavaScript или TypeScript с использованием нативных конструкций. Это позволяет разработчикам жестко определять типы данных, связи между таблицами, индексы и ограничения прямо в коде приложения. В результате обеспечивается сквозную типизацию — от самого нижнего слоя таблиц до верхнеуровневых API-маршрутов.

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

Ранее в разговоре авторы детально разбирали интеграцию Neon Serverless Postgres и менеджмент переменных окружения (.env), необходимых для авторизации в облаке.

Когда схема базы данных описывается через Drizzle ORM, процесс управления изменениями кардинально упрощается и разделяется на два этапа: декларативное описание таблиц (например, через функции pgTable, serial, text) и автоматическую генерацию SQL-файлов. Drizzle программно сравнивает текущее состояние файлов схем с предыдущими сохраненными слепками (snapshots) и самостоятельно формирует чистые, оптимизированные SQL-миграции в специальной директории проекта.

Такой подход полностью нивелирует человеческий фактор. Разработчику больше нет необходимости вручную составлять комплексные команды CREATE TABLE или ALTER TABLE, рискуя нарушить целостность данных при переносе изменений из локальной среды на продакшен-сервер. Более того, представление схемы в виде стандартного кода упрощает совместную работу в команде, превращая любые изменения структуры базы данных в прозрачный процесс обычного код-ревью через пул-реквесты. Благодаря отсутствию тяжеловесных абстракций, Drizzle генерирует максимально производительный код, что критически важно для минимизации «холодного старта» в бессерверных функциях.

Разработка CLI-утилиты для автоматизации миграций через TSX 2:58:55

Определения схем на уровне исходного кода не имеют смысла без надежного механизма их доставки в реальную базу данных. Чтобы автоматизировать этот процесс и не выполнять команды обновления вручную при каждом изменении схемы, разрабатывается автономная CLI-утилита (интерфейс командной строки). В качестве надежного фундамента для разбора параметров и флагов запуска используется стандартный глобальный объект Node.js — process.argv.

Для изоляции пользовательских или системных аргументов командной строки применяется метод slice(2). Этот прием позволяет отсечь первые два элемента массива, которые содержат пути к самому исполняемому файлу Node.js и к запускаемому скрипту, оставляя только чистые параметры. Создаваемая CLI-утилита выполняет строгую первичную валидацию поступающих данных: если количество переданных параметров не соответствует жестко заданному числу, скрипт аварийно завершает работу с помощью функции process.exit(1). При этом в консоль выводится понятная инструкция по корректному использованию команды, предотвращающая неверные действия разработчика.

Для бесшовного запуска TypeScript-скриптов без рутинной стадии предварительной компиляции в JavaScript применяется современный инструмент TSX (TypeScript Execute). Выполнение команд через npx TSX позволяет компилировать и запускать код налету с помощью сверхбыстрого сборщика esbuild. Так как операции взаимодействия с облачной СУБД Neon носят асинхронный характер, логика применения миграций заворачивается в промисы с конструкцией .then().catch().

В случае успешного выполнения операции утилита выводит сообщение об обновлении секретов или успешном накатывании схемы, после чего корректно закрывает сессию с кодом 0. Если же происходят сетевые сбои, проблемы с правами доступа или синтаксические ошибки, выполнение перехватывается блоком catch. Он выводит детальный лог ошибки в консоль и возвращает код завершения 1, сигнализируя внешней системе о сбое.

Ранее в разговоре упоминались основы Serverless-архитектуры и безопасное хранение секретов в AWS SSM, а автоматизация через CI/CD пайплайны в GitHub Actions будет подробно разобрана в последующих главах.

Создание подобной CLI-утилиты делает слой миграций абсолютно предсказуемым и изолированным. Скрипт может одинаково успешно запускаться как локально на машине разработчика для проверки гипотез, так и внутри конвейеров автоматизации. База данных обновляется до актуального состояния схемы Drizzle полностью автоматически, гарантируя, что структура таблиц всегда строго синхронизирована с текущей версией исходного кода приложения.

🛡️ Надежность данных: Валидация через Zod 3:21:03

Когда мы строим современное API, особенно в связке с Serverless Node.js, вопрос «что именно прислал нам клиент?» становится вопросом жизни и смерти приложения. В этом фрагменте мы видим, как во время тестирования системы возникают ошибки — например, когда фронтенд пытается обратиться к несуществующей функции или передает некорректные данные. Ранее в курсе мы уже упоминали основы работы с Zod, но именно на этапе интеграции с реальными запросами становится понятно, почему эта библиотека — не роскошь, а страховой полис разработчика.

Архитектура безопасности: Зачем Zod в Serverless-стеке 3:27:24

Zod — это библиотека для декларативного описания схем данных с автоматическим выводом типов (Type Inference) для TypeScript. В нашем проекте она выполняет роль «вышибалы» на входе в API-эндпоинты. Когда мы работаем с AWS Lambda (тему настройки которой мы подробно разбирали в первой главе), каждый вызов функции стоит ресурсов. Пропускать «битые» данные глубже в бизнес-логику или, тем более, в базу данных — это верный способ получить Internal Server Error.

Основные преимущества внедрения Zod в наш пайплайн:

Как мы видим на практике, когда разработчик допускает опечатку в названии функции (например, вызывая getLeads вместо корректного listLeads), система возвращает ошибку. Zod помогает минимизировать такие ситуации на уровне входящих параметров, гарантируя, что логика CRUD (которую мы реализовывали через Drizzle в восьмой главе) получит только валидные объекты.


Практика внедрения: Создание схем для эндпоинтов 3:38:01

Для работы с лидами (leads) в нашем API необходимо создать схему, которая будет описывать ожидаемый объект. Это критично, когда мы начинаем проксировать запросы через другие сервисы или интегрироваться с фронтендом на Next.js.

Типичная схема для создания лида с использованием Zod выглядит следующим образом:

  1. Определение схемы: Мы импортируем z и описываем объект. Например, email: z.string().email().
  2. Валидация тела запроса: Внутри обработчика Express (который, как отмечалось ранее, отлично работает в Serverless благодаря своей легкости), мы берем req.body и пропускаем через схему.
  3. Обработка результата: Если данные не прошли проверку, мы возвращаем статус 400 Bad Request с детальным описанием того, что именно пошло не так.

Это избавляет нас от громоздких конструкций if (!req.body.email) ... и делает код чистым и читаемым. В процессе демонстрации интеграции с Vercel мы видим, как отправка POST-запроса с данными email: abc123@gmail.com должна проходить через этот фильтр безопасности. Если поле будет отсутствовать или формат будет нарушен, API должно среагировать мгновенно, не нагружая базу данных Neon.


Обработка ошибок и предотвращение «Internal Server Error» 3:42:50

Одной из самых раздражающих проблем при разработке является внезапное падение сервера. В нашем фрагменте автор сталкивается с этим, когда API возвращает 500-ю ошибку. Хотя в данном конкретном случае проблема была в опечатке в коде, в реальных условиях 90% таких ошибок вызваны неожиданным форматом входных данных (например, null там, где ожидалась строка).

Использование Zod позволяет нам:

В конечном итоге, внедрение Zod превращает хаотичные HTTP-запросы в предсказуемый поток данных. Это создает прочный фундамент для дальнейшей автоматизации через CI/CD пайплайны и GitHub Actions, гарантируя, что даже если мы внедрим изменения в Dev-ветку, структура данных останется целостной и защищенной.

🚀 Развертывание и масштабируемость: от API к CI/CD и Vercel 3:46:29

Автоматизация процессов доставки программного обеспечения позволяет разработчикам сосредоточиться на написании кода, минимизируя ручное вмешательство в инфраструктуру. Использование таких платформ, как Vercel, в связке с гибкими CI/CD пайплайнами, открывает широкие возможности для управления средами разработки и продуктовыми релизами.

CI/CD пайплайны и автоматизация через GitHub Actions 3:52:11

Настройка автоматических процессов сборки и развертывания является критически важным этапом современного цикла разработки. Благодаря интеграции с GitHub Actions, каждое обновление в репозитории может инициировать цепочку событий: от тестирования до деплоя в различные окружения.

Важной практикой здесь является создание динамических веток базы данных для каждой Pull Request задачи. Это позволяет изолировать тестовую среду разработки (Dev-окружение) от продуктовой, обеспечивая чистоту данных и безопасность экспериментов. Как отмечалось ранее в обсуждении, автоматизация инфраструктуры через CLI значительно упрощает этот процесс, позволяя разработчикам создавать и удалять ветки БД «на лету» без необходимости ручного управления. При правильной настройке CI/CD, разработчики могут легко переключаться между стадиями разработки, тестирования и продакшена, просто управляя ветками в Git.

Интеграция с Vercel и Next.js 3:47:09

Хотя технически возможно развернуть чистое Express.js приложение напрямую в Vercel, рекомендуется использовать Next.js как основной фреймворк для фронтенда и API-слоя. Vercel оптимизирован под Next.js, что обеспечивает бесшовную работу серверных функций и клиентской части.

Для объединения фронтенда с существующим API в серверной среде часто используется механизм rewrites. Настройка vercel.json позволяет перенаправлять запросы (например, все запросы с префиксом /api) непосредственно на обработчик Express.js, скрывая архитектурные сложности от конечного пользователя.

Использование такого подхода позволяет разработчику плавно мигрировать функционал из классического Express.js в современную архитектуру Next.js, получая преимущества обеих сред при минимальных затратах на переписывание бизнес-логики.

💬 Цитаты

«Serverless is really just focusing on the code. You deploy your code and then somebody else makes sure that all the systems scale up to meet the demand.»

«The idea here is we want to highlight what branching is all about—it's that point in time snapshot of our database.»

«Drizzle ORM is going to handle that interaction for us so we can just write a bunch of JavaScript instead of writing a bunch of SQL»

«The key of all of this with whenever it comes to inserting data from the Internet is you almost always want to clean that data and validate it before you want to send it into the database.»

«Я никогда не вставлял никакие AWS-ключи сюда... Я мог буквально просто поделиться этим бэкендом, этим API, как посчитаю нужным.»

👥 Спикеры
📖 Термины
Serverless
Модель облачных вычислений, при которой провайдер управляет серверами, а разработчик фокусируется только на коде.
Neon Postgres
Serverless-база данных на основе Postgres с поддержкой мгновенного ветвления данных.
Drizzle ORM
Легковесная ORM для Node.js, обеспечивающая типизированную работу с базой данных.
Zod
Библиотека для декларативной валидации данных с автоматическим выводом TypeScript-типов.
Технологии и IT AWS Lambda Serverless Framework Neon Postgres Drizzle ORM Node.js