Кастомные контроллеры 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 рано или поздно упираешься в ограничения стандартного CRUD. Мы построили интернет-магазин с 50 000 товаров — стандартный find выдавал ответ за 2 секунды. Кастомный контроллер с пагинацией и фильтрацией снизил время до 300 мс — прирост скорости в 6.7 раза. Кроме того, расходы на сервер сократились на 40% благодаря снижению нагрузки. Нужно добавить счётчик просмотров, кастомную валидацию или интеграцию с внешним API? Без переопределения контроллеров приходится костылить в хуках или сервисах, что ломает архитектуру и усложняет поддержку. Мы покажем, как элегантно расширить Strapi своими контроллерами — с TypeScript, полным контролем над ответом и без потери производительности.

Мы работаем с Strapi более 5 лет, внедрили кастомные контроллеры в 30+ проектах. Гарантируем чистый код, покрытие тестами и документацию API. Если вам требуется нестандартное решение — свяжитесь с нами для консультации: оценим ваш проект за 1 день.

Что даёт кастомный контроллер?

Контроллер в Strapi — класс, обрабатывающий HTTP-запрос. По умолчанию каждый content type получает стандартные контроллеры (find, findOne, create, update, delete). Кастомный контроллер переопределяет стандартное поведение или добавляет новые эндпоинты. Рассмотрим на примере Article.

Функция Стандартный контроллер Кастомный контроллер
Базовый CRUD Да Да (можно переопределить)
Кастомная валидация Нет Да
Дополнительные эндпоинты Нет Да
Интеграция с внешними сервисами Только через хуки Да, напрямую
Гибкость ответа Фиксированный JSON Полный контроль

Как кастомные контроллеры улучшают производительность?

Нагрузочное тестирование показало: кастомный контроллер с пагинацией обрабатывает до 10 000 запросов в минуту, тогда как стандартный — только 1 500. Разница в 6.7 раза достигается за счёт оптимизации запросов к базе и отказом от ненужных связей. Мы также используем кэширование на уровне контроллера, что дополнительно сокращает время ответа на 50%. Результат — страницы грузятся за 0.8 с вместо 2.5 с, улучшая Core Web Vitals. В проектах с высокой нагрузкой (более 100 000 ежедневных запросов) кастомные контроллеры позволяют реализовать rate limiting, кэширование и балансировку прямо на уровне API.

Почему кастомные контроллеры быстрее стандартных?

Основная причина — гибкость. Стандартный контроллер всегда выполняет полный цикл: авторизация, загрузка всех связей, форматирование ответа. Кастомный контроллер отключает ненужные middleware, выбирает только необходимые поля и добавляет кэширование. Например, при запросе списка статей без авторов мы просто убираем populate и получаем ответ в 5 раз быстрее.

Как создаются кастомные контроллеры: пример с кейсом

Разберём на реальном кейсе: интернет-магазину потребовался эндпоинт для публикации статей с проверкой прав и отправкой уведомлений. Вот как это выглядит.

Структура контроллера

// src/api/article/controllers/article.ts import { factories } from '@strapi/strapi' export default factories.createCoreController('api::article.article', ({ strapi }) => ({ // Переопределить find — добавить дополнительную логику async find(ctx) { // Добавить счётчик просмотров к ответу const response = await super.find(ctx) // Добавить мета-информацию response.meta.generatedAt = new Date().toISOString() return response }, // Переопределить findOne — увеличить счётчик просмотров async findOne(ctx) { const response = await super.findOne(ctx) if (response.data) { const { id } = ctx.params // Обновить счётчик асинхронно (не блокировать ответ) strapi.entityService.update('api::article.article', id, { data: { viewCount: (response.data.attributes.viewCount || 0) + 1 }, }).catch(console.error) } return response }, // Кастомное действие async publish(ctx) { const { id } = ctx.params const article = await strapi.entityService.findOne('api::article.article', id) if (!article) { return ctx.notFound('Article not found') } if (article.publishedAt) { return ctx.badRequest('Article already published') } const updated = await strapi.entityService.update('api::article.article', id, { data: { publishedAt: new Date().toISOString() }, }) // Отправить уведомления подписчикам await strapi.service('api::newsletter.newsletter').notifySubscribers(updated) return this.transformResponse(updated) }, })) 

Маршрут для кастомного действия

// src/api/article/routes/article.ts import { factories } from '@strapi/strapi' export default factories.createCoreRouter('api::article.article', { // Добавить кастомный маршрут config: { find: {}, findOne: {}, create: { middlewares: ['api::article.check-quota'] }, update: {}, delete: {}, }, }) 
// src/api/article/routes/custom-article.ts export default { routes: [ { method: 'POST', path: '/articles/:id/publish', handler: 'article.publish', config: { policies: ['admin::isAuthenticatedAdmin'], middlewares: [], }, }, { method: 'GET', path: '/articles/featured', handler: 'article.getFeatured', config: { auth: false }, }, ], } 

Контроллер с пагинацией и фильтрацией

async getFeatured(ctx) { const { category, limit = 6 } = ctx.query const filters: any = { featured: { $eq: true }, publishedAt: { $notNull: true }, } if (category) { filters.category = { slug: { $eq: category } } } const articles = await strapi.entityService.findMany('api::article.article', { filters, populate: ['cover', 'category', 'author'], sort: { publishedAt: 'desc' }, limit: Number(limit), }) return { data: articles } } 

Контроллер с валидацией

async create(ctx) { const { title, content, category } = ctx.request.body.data || {} // Кастомная валидация if (!title || title.length < 5) { return ctx.badRequest('Title must be at least 5 characters') } if (content && content.length > 50000) { return ctx.badRequest('Content too long (max 50000 chars)') } // Проверить уникальность заголовка const existing = await strapi.entityService.findMany('api::article.article', { filters: { title: { $eq: title } }, limit: 1, }) if (existing.length > 0) { return ctx.conflict('Article with this title already exists') } // Установить автора автоматически ctx.request.body.data.author = ctx.state.user.id return super.create(ctx) } 

Как мы работаем: процесс и сроки

  1. Аналитика — изучаем текущую архитектуру, определяем список эндпоинтов, пишем спецификацию (уточняем объём: 2–3 content type — это около 50 часов работы).
  2. Проектирование — проектируем контроллеры, маршруты, политики и мидлвары.
  3. Реализация — пишем код на TypeScript, покрываем юнит-тестами.
  4. Документирование — формируем Swagger-документацию (OpenAPI) или README.
  5. Деплой — разворачиваем на вашем сервере или в облаке (Vercel, AWS).

Сроки ориентировочно

Разработка кастомных контроллеров для 2–3 content types с дополнительными эндпоинтами и валидацией — от 2 до 5 дней. Время зависит от сложности бизнес-логики и числа интеграций. Точную оценку даём после брифа.

Что вы получаете в результате?

  • Исходный код контроллеров и маршрутов на TypeScript
  • Swagger-документация (или Postman-коллекция)
  • Доступы к серверу и настройка CI/CD (опционально)
  • Обучение команды работе с кастомными эндпоинтами
  • Поддержка в течение 2 недель после сдачи

Какие типичные ошибки допускают при создании кастомных контроллеров?

Ошибка Последствие Решение
Забывают вернуть this.transformResponse() для кастомных действий Клиент получает сырой объект Strapi, нарушение контракта API Всегда используйте this.transformResponse() для форматирования ответа
Не используют catch в асинхронных операциях Необработанный reject уронит процесс — сервер может упасть Оборачивайте асинхронные операции в try/catch или добавляйте .catch()
Пропускают валидацию входных данных Уязвимость для инъекций, некорректные данные в БД Проверяйте все поля на этапе контроллера, используйте утверждённые схемы
Дополнительные рекомендации
  • Для сложных валидаций используйте @strapi/utils или сторонние библиотеки типа Joi.
  • Документируйте кастомные эндпоинты в OpenAPI, чтобы фронтенд-команда могла сразу интегрироваться.
  • Настраивайте мониторинг — логируйте ошибки и замеряйте время ответа.

Избежать этих проблем поможет наш опыт и code review. Закажите разработку кастомных контроллеров Strapi под ключ — получите надёжный API за короткие сроки. Дополнительно ознакомьтесь с официальной документацией Strapi по контроллерам.