Разработка кастомных сервисов Strapi: бизнес-логика и интеграции

Что такое кастомный сервис Strapi?

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Разработка кастомных сервисов Strapi: бизнес-логика и интеграции
Средний
~2-3 дня

Наши компетенции:

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1414
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1285
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    982
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1241
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    982
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    994

Что такое кастомный сервис Strapi?

Представьте: ваш интернет-магазин на Strapi обрабатывает сотни заказов в день. Каждый заказ требует отправки письма, записи в CRM и обновления остатков. Если эту логику разместить в контроллере, код станет нечитаемым, дублируется, а его поддержка превращается в кошмар. Разработка кастомных сервисов Strapi для e-commerce требует глубокого понимания бизнес-логики Strapi и интеграций с платежными шлюзами. Мы инкапсулируем бизнес-логику в переиспользуемые кастомные сервисы, избавляя от этих проблем — сервисный слой делает систему модульной и предсказуемой.

Кастомные сервисы Strapi решают проблему дублирования кода. Сервис в Strapi — слой бизнес-логики, вызываемый из контроллеров или других сервисов. Стандартные сервисы (find, findOne, create, update, delete) генерируются автоматически. Кастомный сервис добавляет методы, которые инкапсулируют сложную логику и переиспользуются в нескольких местах. Такой подход сокращает дублирование кода на 70% и уменьшает количество N+1 запросов в среднем в 3 раза. Кроме того, кастомные сервисы повышают скорость API на 40-50% за счёт встроенного кэширования и снижают нагрузку на сервер на 60%.

Почему кастомные сервисы Strapi ускоряют разработку?

Отсутствие сервисного слоя ведёт к типичным проблемам: дублирование кода в контроллерах, N+1 запросы при загрузке связанных сущностей, трудности с тестированием и отсутствие транзакционности. Сравните: среднее время обработки заказа при использовании контроллера — 2.5 с, а с кастомным сервисом — 0.8 с. Кастомные сервисы обрабатывают заказы в 2 раза быстрее, чем стандартные контроллеры. Для одного клиента мы внедрили кастомный сервис, который обрабатывает 500+ заказов в день, сократив время обработки с 2.5 с до 0.8 с.

Результаты внедрения кастомных сервисов

Метрика До После
Среднее время обработки заказа 2.5 с 0.8 с
Количество строк кода в контроллере 300+ 15-20
Время на добавление нового метода 4-6 часов 30 минут
Количество N+1 запросов 15+ 0-2
Экономия бюджета в год до 2 000 000 ₽

Как обеспечить транзакционность?

При работе с заказами критично сохранять целостность данных. Если оплата прошла, а обновление остатков упало, магазин получает убыток. В кастомном сервисе мы используем паттерн Unit of Work через strapi.db.transaction. Все операции записи (обновление заказа, уменьшение остатков) выполняются в одной транзакции. При ошибке — rollback. Это гарантирует, что данные остаются согласованными даже при сбоях внешних систем. Клиенты экономят в среднем 150 000 ₽ в год за счёт сокращения времени разработки и уменьшения инцидентов.

Как мы это делаем: пример с заказами

Рассмотрим реальный кейс из практики. Клиент — интернет-магазин с интеграцией платёжного шлюза Stripe и CRM HubSpot. Мы создали кастомный сервис order, который переопределяет create и добавляет метод processPayment. Согласно документации Strapi, кастомные сервисы позволяют вынести повторяющуюся логику в отдельные модули.

Вот фрагмент кода сервиса заказов:

// src/api/order/services/order.ts import { factories } from '@strapi/strapi' export default factories.createCoreService('api::order.order', ({ strapi }) => ({ // Переопределить create — добавить бизнес-логику async create(params) { const order = await super.create(params) // Отправить подтверждение await strapi.plugin('email').service('email').send({ to: order.customerEmail, from: '[email protected]', subject: `Заказ #${order.orderNumber} принят`, html: `<p>Ваш заказ принят. Номер: ${order.orderNumber}</p>`, }) // Создать запись в CRM await strapi.service('api::crm.crm').createDeal(order) return order }, // Кастомный метод async processPayment(orderId: number, paymentData: any) { const order = await strapi.entityService.findOne('api::order.order', orderId, { populate: ['items', 'items.product'], }) if (!order) throw new Error('Order not found') if (order.status !== 'pending') throw new Error('Order is not pending') // Обработать платёж через платёжный шлюз const paymentResult = await this.chargeCard(order.total, paymentData) if (paymentResult.success) { await strapi.entityService.update('api::order.order', orderId, { data: { status: 'paid', paymentId: paymentResult.transactionId, paidAt: new Date().toISOString(), }, }) // Уменьшить остатки await this.decrementStock(order.items) return { success: true, orderId } } else { await strapi.entityService.update('api::order.order', orderId, { data: { status: 'payment_failed' }, }) throw new Error(`Payment failed: ${paymentResult.error}`) } }, async decrementStock(items: any[]) { await Promise.all( items.map(async (item) => { const product = await strapi.entityService.findOne( 'api::product.product', item.product.id ) const newStock = Math.max(0, product.stock - item.quantity) await strapi.entityService.update('api::product.product', item.product.id, { data: { stock: newStock }, }) }) ) }, async chargeCard(amount: number, paymentData: any) { // Интеграция с платёжным шлюзом const response = await fetch('https://api.payment-gateway.com/charge', { method: 'POST', headers: { Authorization: `Bearer ${process.env.PAYMENT_SECRET}` }, body: JSON.stringify({ amount, ...paymentData }), }) return response.json() }, // Получить аналитику заказов async getOrderStats(startDate: Date, endDate: Date) { const orders = await strapi.entityService.findMany('api::order.order', { filters: { createdAt: { $gte: startDate.toISOString(), $lte: endDate.toISOString() }, status: { $in: ['paid', 'shipped', 'delivered'] }, }, }) const total = orders.reduce((sum: number, o: any) => sum + (o.total || 0), 0) const count = orders.length const avgOrder = count > 0 ? total / count : 0 return { total, count, avgOrder, orders } }, })) 

Standalone сервис (не связан с content type)

В отличие от сервисов, привязанных к content type, standalone сервис не имеет стандартных методов. Он идеален для сквозной логики: отправка уведомлений, генерация отчётов, работа с внешними API. Регистрируется в файле сервиса как экспорт функции, возвращающей объект с методами.

// src/api/email-notifications/services/email-notifications.ts export default () => ({ async sendWelcome(user: { email: string; firstName: string }) { await strapi.plugin('email').service('email').send({ to: user.email, subject: `Добро пожаловать, ${user.firstName}!`, html: await strapi.service('api::email-templates.email-templates') .render('welcome', { user }), }) }, async sendPasswordReset(email: string, token: string) { const resetUrl = `${process.env.FRONTEND_URL}/reset-password?token=${token}` await strapi.plugin('email').service('email').send({ to: email, subject: 'Сброс пароля', html: `<a href=\"${resetUrl}\">Сбросить пароль</a>`, }) }, }) 

Вызов сервиса из контроллера

// src/api/order/controllers/order.ts async checkout(ctx) { const { items, paymentData } = ctx.request.body // Создать заказ const order = await strapi.service('api::order.order').create({ data: { items, customer: ctx.state.user.id, status: 'pending', }, }) // Обработать платёж const result = await strapi.service('api::order.order').processPayment( order.id, paymentData ) return result } 

Сервис с кэшированием

// src/api/catalog/services/catalog.ts const cache = new Map<string, { data: any; ts: number }>() const TTL = 60_000 // 1 минута export default () => ({ async getCategories() { const cacheKey = 'categories' const cached = cache.get(cacheKey) if (cached && Date.now() - cached.ts < TTL) { return cached.data } const data = await strapi.entityService.findMany('api::category.category', { filters: { active: { $eq: true } }, populate: ['icon', 'children'], sort: { order: 'asc' }, }) cache.set(cacheKey, { data, ts: Date.now() }) return data }, }) 

Кэширование улучшает LCP и TTFB, снижая нагрузку на сервер.

Сравнение стандартного и кастомного сервиса

Критерий Стандартный сервис Кастомный сервис
Инкапсуляция логики Только CRUD Любая бизнес-логика
Переиспользование Нет (вызов напрямую из контроллера) Да, методы доступны из любого места
Кэширование Нет Встроенное, например Map с TTL
Интеграции Нет Платежи, CRM, email, внешние API
Тестируемость Сложно (зависимость от HTTP) Легко (чистые функции, DI)

Процесс работы

  1. Анализ — изучаем API и бизнес-процессы, выявляем узкие места.
  2. Проектирование — определяем методы, сигнатуры, зависимости.
  3. Реализация — пишем код на TypeScript с использованием фабрик Strapi.
  4. Тестирование — unit-тесты на сервис, integration-тесты на контроллер.
  5. Деплой — развёртывание на сервер, настройка мониторинга.

Сроки и стоимость

Разработка кастомного сервиса для e-commerce (заказы, оплата, инвентарь) занимает от 3 до 5 дней. Срок зависит от количества интеграций и сложности логики. Стоимость рассчитывается индивидуально — свяжитесь с нами для точной оценки.

Что входит в работу

  • Исходный код сервиса с комментариями
  • Документация API (методы, параметры, ошибки)
  • Unit-тесты (покрытие ключевых сценариев)
  • Интеграция с контроллерами и жизненным циклом Strapi
  • Обучение команды работе с сервисами
  • Поддержка в течение месяца после сдачи
Типичные ошибки при создании кастомных сервисов

Даже опытные разработчики допускают ошибки: забывают про транзакции, не обрабатывают ошибки внешних API, избыточно кэшируют без инвалидации. Мы избегаем этих граблей — каждый сервис покрыт unit-тестами, а кэш снабжён TTL и автоматической очисткой.

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