Создайте надежный API узла с TypeORM, используя транзакции
Javascript и NodeJS имеют одну из самых популярных экосистем для разработки современных веб-приложений. Он содержит множество полезных ресурсов и фреймворков, которые облегчают нам часть работы.
Одной из основных проблем сегодня при создании API, который будет общедоступным, является обеспечение надежности и безопасности предоставляемого сервиса. Сегодня мы увидим, как транзакции базы данных — отличный способ улучшить качество службы API и избежать множества проблем в вашем приложении.
Пример интернет-магазина
Давайте рассмотрим простой Node Express API, который мы разработали для управления некоторыми нашими интернет-магазинами.
В этом примере мы собираемся развернуть базу данных PostgreSQL через контейнер Docker.
API был настроен с использованием TypeScript и фреймворка TypeORM для взаимодействия с базой данных.
Конечные точки API
Чтобы клиент мог взаимодействовать с нашим приложением, API предоставляет следующие конечные точки на /order router:
- Открытый приказ
- Порядок обновления
- Полный заказ
- Получить заказ
Затем мы можем открыть заказ с почтовым запросом в конечной точке /order, указав shopId, желаемые продукты и их количество:
{ "shopId": 1, "productsRelation": [ { "productId": 1, "quantity": 2}, { "productId": 2, "quantity": 1} ], "clientEmail": "[email protected]" }
В этом простом API мы не собираемся учитывать все функции безопасности, которые должны быть в реальном сервере электронной коммерции, поскольку мы стараемся сделать его максимально простым. При открытом заказе пользователь может обновлять его, добавлять или удалять товары по своему усмотрению.
В конце этого процесса заказ может быть подтвержден в процессе оформления заказа по маршруту /order/complete . Что будет обрабатываться специальным методом в классе OrderService:
Мы считаем, что маршрут completeOrder будет отвечать в процессе оформления заказа за:
- Проверяя оплату заказа, для простоты мы собирались предположить, что она будет зарегистрирована в нашей базе данных.
- Отправка уведомления пользователю по электронной почте и регистрация его в нашей базе данных
- Обновление записи заказа в нашей базе данных
Наш API не очень надежен
Обычно описанный выше метод работает без проблем при обработке любого заказа клиента. Однако мы должны учитывать возможность того, что что-то пойдет не так в середине этого процесса.
Что делать, если произошла ошибка в тот момент, когда клиент должен был быть уведомлен по электронной почте? Это означает, что процесс оформления заказа будет терпеть неудачу прямо посреди него, а мы только что завершили часть всей операции!
Платеж был подтвержден, но не было уведомления по электронной почте, а статус заказа не был обновлен. Мы получаем нашу базу данных в середине процесса оформления заказа.
Как мы можем решить эту проблему?
Сначала мы можем подумать о решении этой проблемы, сначала обновив запись заказа в базе данных, а затем уведомив клиента по электронной почте о том, что заказ выполнен. Хотя иногда это может работать, это не является последовательным решением. Что, если нам придется ввести еще один шаг в процессе оформления заказа? Это может быть не так просто, как в этом случае.
Здесь в игру вступают транзакции базы данных. Транзакция — это просто блок операций «все или ничего». Либо все они работают гладко, либо один из них дает сбой, и каждая сделанная модификация откатывается в БД перед транзакцией.
Эта концепция широко используется для систем баз данных. В PostgreSQL команды запуска и завершения транзакции — START и COMMIT:
START; UPDATE product SET stock_quantity = 0 WHERE id = 2; UPDATE order SET order_status = 'awaiting_delivery' WHERE id = 1; INSERT into email VALUES ('[email protected]', 'Thank you for your purchase'); COMMIT;
Если мы передумаем о каких-либо наших изменениях, мы можем просто запустить команду ROLLBACK вместо COMMIT. Подробнее о них можно узнать в официальной документации.
Использование транзакций с TypeORM
К счастью, TypeORM — довольно полная структура, которая также поддерживает транзакции. Следуя официальной документации, их можно настроить по-разному.
В этой статье я собираюсь показать вам тот, который я принял в своих проектах. Это достигается путем помещения всей бизнес-логики в вспомогательный элемент с именем transactionContext:.
На вход поступает функция, которая получает в качестве аргумента TypeORM EntityManager и отвечает за выполнение всей бизнес-логики.
Возможны два исхода:
- Либо оболочка транзакции успешно выполнит ввод serviceMethod, вернет свой вывод и зафиксирует транзакцию.
- Либо внутри serviceMethod будет выброшена ошибка, и вся транзакция будет отброшена к своему состоянию до начала транзакции.
Теперь мы можем применить нашу оболочку к нашим контроллерам маршрутов и решить нашу проблему с маршрутом оформления заказа:
Каждое взаимодействие с БД будет осуществляться через transactionManager, его можно внедрить везде, где нам нужно выполнить любой запрос.
Возвращаясь к методу completeOrder, мы имеем:
Где мы внедряем диспетчер транзакций везде, где хотим общаться с базовой БД. Теперь, если где-то в нашем коде есть ошибка, он будет откатывать любые изменения, внесенные в базу данных, прежде чем выдать ошибку.
Весь код API доступен в этом git-репозитории.
Отныне вы сможете создавать гораздо более надежные API и сервисы с помощью Node и TypeORM. Также я хотел бы уточнить, что это только из возможных подходов обработки транзакций базы данных с помощью TypeORM, вы можете обратиться к официальной документации, чтобы узнать больше о том, как они могут применяться.
Спасибо за внимание и доведение до конца!
Бит: почувствуйте мощь компонентно-ориентированной разработки
Скажи привет Bit. Это инструмент №1 для разработки приложений на основе компонентов.
С помощью Bit вы можете создать любую часть своего приложения в виде «компонента», который можно компоновать и использовать повторно. Вы и ваша команда можете совместно использовать набор компонентов для более быстрой и последовательной совместной разработки большего количества приложений.
- Создавайте и компонуйте «строительные блоки приложения»: элементы пользовательского интерфейса, полные функции, страницы, приложения, бессерверные или микросервисы. С любым стеком JS.
- С легкостью делитесь и повторно используйте компоненты в команде.
- Быстро обновляйте компоненты в разных проектах.
- Делайте сложные вещи простыми: Монорепо, дизайн-системы и микрофронтенды.
Попробуйте Bit бесплатно и с открытым исходным кодом→