Перейти к содержимому

Shop API

Fluttrium Shop API — публичный GraphQL для сайтов магазинов. Один адрес на всю платформу, магазин выбирается токеном в заголовке. Через него витрина читает каталог и контент, ведёт корзину и оформляет заказ.

POST https://api.fluttrium.store/shop-api
Заголовок Значение Зачем
content-type application/json Тело — { "query": "…", "variables": { … } }
vendure-token токен магазина Выбирает магазин. Токен выдаёт Fluttrium при подключении
authorization Bearer <токен сессии> Сессия покупателя: корзина, вход. Для каталога не нужен
accept-language ru Язык сообщений об ошибках. Без него сообщения на английском

Язык контента (названия, описания) задаётся параметром адреса ?languageCode=ru. Без него — язык магазина по умолчанию.

Корзина и вход привязаны к сессии. Сессию заводит сервер платформы: на первом же запросе, который её касается (даже на чтении activeOrder), он возвращает токен в заголовке ответа vendure-auth-token.

  1. Первый запрос корзины идёт без authorization.

  2. Из ответа возьмите заголовок vendure-auth-token и сохраните его на стороне сервера витрины — например, в httpOnly-cookie.

  3. Все следующие запросы этого покупателя отправляйте с authorization: Bearer <токен>.

  4. Если в ответе пришёл другой vendure-auth-token (например, после входа), замените сохранённый.

SDK берёт на себя заголовки, таймауты, сессию и разбор ошибок. Пакет публикуется в реестре платформы и открыт на чтение без логина.

.npmrc
@fluttrium:registry=https://npm.fluttrium.store/
import { createShopClient, StorefrontContentDocument } from '@fluttrium/shop-sdk';
const shop = createShopClient({
url: 'https://api.fluttrium.store/shop-api',
channelToken: process.env.SHOP_CHANNEL_TOKEN!, // токен магазина
});
// Публичный запрос с кешем Next.js на минуту.
const { data } = await shop.request(StorefrontContentDocument, undefined, {
fetchOptions: { next: { revalidate: 60, tags: ['content'] } },
});
// Запрос в сессии покупателя: токен из cookie туда, новый — обратно в cookie.
const { data: cart, authToken } = await shop.request(ActiveOrderDocument, undefined, {
authToken: sessionFromCookie,
});
if (authToken && authToken !== sessionFromCookie) saveSessionCookie(authToken);

Версия SDK равна версии платформы. Ставьте ту, что сейчас на сервере: схема в пакете описывает именно её. Свои запросы витрина пишет сама и получает типы из той же схемы через @fluttrium/shop-sdk/codegen — см. Витрина на Next.js.

Ошибки SDK — ShopApiError с полем kind:

kind Что случилось
config Не задан адрес или токен, документ не в строковом режиме codegen
network Сервер платформы недоступен
timeout Нет ответа за таймаут (по умолчанию 15 с)
aborted Запрос отменён вызывающим
http Ответ без данных GraphQL (например, 502)
graphql Сервер ответил ошибками GraphQL, коды — в errors[].extensions.code

Частичный ответ (корневые поля пришли, упало вложенное) исключением не считается: данные отдаются, ошибки уходят в onPartialErrors. Иначе витрина сообщила бы о сбое уже выполненной мутации, и повтор добавил бы товар дважды.

Цены во всех ответах — в копейках: 290000 — это 2 900 ₽.

query Collections {
collections(options: { topLevelOnly: true, take: 100 }) {
items {
slug
name
position
children { slug name position }
}
}
}

Ошибки приходят двумя способами.

Ошибки бизнес-логики — данными: мутация возвращает объект с errorCode и message вместо заказа. Их нужно разбирать и показывать покупателю.

errorCode Когда
INSUFFICIENT_STOCK_ERROR Не хватает остатка, в ответе quantityAvailable
ORDER_MODIFICATION_ERROR Заказ уже ушёл в оплату, менять его нельзя
ORDER_STATE_TRANSITION_ERROR Недопустимый переход состояния заказа
NO_ACTIVE_ORDER_ERROR У сессии нет корзины
GUEST_CHECKOUT_ERROR, EMAIL_ADDRESS_CONFLICT_ERROR Почта принадлежит зарегистрированному покупателю — предложите войти по коду
PAYMENT_DECLINED_ERROR, PAYMENT_FAILED_ERROR Банк отказал или платёж не создан
INVALID_CREDENTIALS_ERROR Неверный или просроченный код входа

Ошибки запроса — в errors[] ответа GraphQL с кодом в extensions.code:

Код Когда
CHANNEL_NOT_FOUND Неверный токен магазина
FORBIDDEN Нет доступа: например, чужой заказ в orderByCode
USER_INPUT_ERROR Неверные аргументы: строки заказа уже нет, take больше 100
Что Предел
Элементов в одном списке (take) 100
Код входа покупателя 1 письмо в минуту, 5 в час, 10 в сутки на почту; 5 попыток на код — подробнее
checkOrderPayment запрос к банку по одному заказу не чаще раза в 3 с
Сервис виджета СДЭК 120 запросов в минуту на магазин и адрес покупателя — подробнее

Shop API отвечает на POST, HTTP-кеш браузеров и прокси его не держит. Кешируйте на сервере витрины, только публичные запросы без сессии. После правки в админке витрина покажет изменение, когда истечёт её кеш.

Схему удобно изучать в GraphiQL: api.fluttrium.store/graphiql/shop. Добавьте заголовок vendure-token с токеном своего магазина во вкладке заголовков, иначе запросы пойдут в канал по умолчанию.