При разработке headless-проектов на Directus стандартная генерация API часто не покрывает бизнес-логику. Типичная ситуация: фронтенд делает 30 запросов для страницы каталога из-за N+1 реляций, фильтры не работают для вложенных полей, а GraphQL выдаёт ошибки при сложных агрегациях. Заказчик теряет пользователей из-за медленной загрузки. Мы — команда с пятилетним опытом внедрения Directus — превращаем API в производительное решение. Наши клиенты экономят до 40% серверных ресурсов и сокращают TTFB с 2 секунд до 200 мс.
Проблемы, которые решаем
N+1 запросов при работе с реляциями
Стандартный REST-запрос /items/articles возвращает только flat-поля. Если фронтенду нужны автор, категория и комментарии — он делает 3 дополнительных запроса на каждый пост. При 20 постах на странице это 60 запросов. Решение — использовать fields=*,author.*,category.*,comments.* с одним запросом. Но если нужно сортировать комментарии или лимитировать их количество — требуется deep-параметр. Мы настраиваем глубокие populate с кастомными сортировками и лимитами, снижая количество запросов до 1–2.
Фильтрация по связанным коллекциям
Частая задача: показать статьи только из определённой категории, но категория — связанная запись. В Directus это делается через filter[category][slug][_eq]=tech. Однако OR-условия с вложенными связями могут привести к некорректным результатам. Например, filter[_or][0][title][_icontains]=react&filter[_or][1][content][_icontains]=react работает, но если нужно объединить с фильтром по автору — синтаксис усложняется. Мы используем кастомные эндпоинты на Flows для сложной логики.
Агрегации с группировкой
Для дашбордов часто нужна сумма продаж по месяцам. Directus поддерживает aggregate[sum]=total&groupBy[]=status, но в одном запросе нельзя сгруппировать по двум разным полям. Мы применяем SDK и пишем кастомные SQL-запросы через миграции.
Как мы это делаем: стек и кейс из практики
Проект нашего клиента — интернет-магазин на Next.js + Directus 10. Задача: построить API для каталога с фильтрами (цена, бренд, характеристики), поиском через Meilisearch, realtime-обновлением корзины. Стек: Directus (REST + WebSocket), Meilisearch для полнотекстового поиска, Redis для кэширования.
Кейс с агрегацией: Нужно было вывести средний чек по дням. Через стандартный REST это невозможно — только один тип агрегации на запрос. Написали кастомный эндпоинт на Flows с SQL-запросом:
SELECT DATE(date_created) as day, AVG(total) as avg_check FROM orders WHERE status = 'paid' GROUP BY day ORDER BY day; Результат: 1 запрос вместо 30, скорость дашборда выросла в 4 раза. Заказчик сэкономил $2000 в месяц на кэшировании и CDN.
Процесс работы
- Аналитика: ревизия текущих запросов, выявление узких мест (Core Web Vitals, количество запросов).
- Проектирование: выбираем REST, GraphQL или WebSocket под задачи. Прописываем схему реляций и фильтров.
- Реализация: настройка эндпоинтов, кастомных Flows, оптимизация через
fieldsиdeep. Для поиска подключаем Meilisearch или Elasticsearch. - Тест: нагрузочное тестирование (k6), проверка на 1000 concurrent запросов.
- Деплой: настройка rate limiting, CORS, SSL, кэширования (Redis/Varnish).
Как настроить GraphQL в Directus?
Включите GraphQL, указав в .env:
GRAPHQL_SDLFILE=/tmp/schema.graphql GraphQL доступен по /graphql. В production отключаем интроспекцию через GRAPHQL_INTROSPECTION=false. Используйте мутации для создания записей и subscription для realtime.
Почему REST API быстрее GraphQL?
В Directus REST API использует кэширование на уровне базы данных (ключи запроса), а GraphQL — нет. Для простых выборок REST даёт меньший latency (на 20–30%). Но GraphQL удобнее для сложных вложенных запросов с разными полями. Выбор зависит от задачи: для публичных эндпоинтов — REST, для админ-панелей — GraphQL.
Как интегрировать поиск через Meilisearch?
Meilisearch подключается как сервис в Directus через Hook или Flow. Настраиваем индексацию полей, релевантность и фильтры. Пример конфигурации:
{ "index": "articles", "primaryKey": "id", "searchableAttributes": ["title", "content"], "filterableAttributes": ["status", "category_id"] } После синхронизации данные доступны через отдельный эндпоинт. Результат — поиск за 10-50 мс вместо 500+ мс при полнотекстовом поиске в PostgreSQL.
Сравнение REST и GraphQL
| Критерий | REST | GraphQL |
|---|---|---|
| Кэширование | Встроенное (URL как ключ) | Отсутствует (нужно настраивать) |
| Overfetching | Да (если не указаны fields) | Нет (возвращает только запрошенные поля) |
| Вложенные запросы | Через deep, сложно для OR | Естественно (query language) |
| Производительность | Выше для простых выборок | Ниже из-за парсинга запросов |
| Подходит для | Публичные API, кэширование | Сложные клиентские интерфейсы |
Типичные ошибки при настройке Directus API
| Ошибка | Последствие | Решение |
|---|---|---|
| Неверный синтаксис deep | Ошибка 500, пустой ответ | URL-encode параметры: deep[comments][_sort]=-date |
| Отсутствие индексов | Full scan, медленные запросы | Создать индексы на часто фильтруемые поля |
| Слишком широкие fields | Высокий трафик, медленный ответ | Указывать только необходимые поля |
| Игнорирование кэша | Избыточная нагрузка на БД | Включить кэширование через Varnish/Cloudflare |
Что входит в работу
- Аудит текущих запросов и оптимизация.
- Настройка REST, GraphQL или WebSocket под задачи.
- Написание кастомных эндпоинтов на Flows для сложной логики.
- Интеграция поиска (Meilisearch/Elasticsearch).
- Настройка rate limiting, кэширования, безопасности.
- Документация по API (OpenAPI/Swagger).
- Обучение команды заказчика.
- Поддержка 1 месяц после запуска.
Сроки
Базовая настройка REST/GraphQL — от 2 до 5 дней. Кастомные эндпоинты и сложные агрегации — от 5 до 10 дней. Точные сроки оцениваем после аудита.
Получите бесплатную консультацию по вашему проекту. Закажите аудит Directus API — мы предложим оптимизированное решение.







