Files
market-backOfficce/API.ru.md
2026-02-20 11:01:15 +04:00

16 KiB
Raw Permalink Blame History

Документация API

Справочник эндпоинтов для бэкофиса маркетплейса.
Базовый URL: https://your-api-domain.com/api

🇬🇧 English documentation: API.md


Проекты

Получить все проекты

GET /api/projects

Ответ 200:
[
  {
    "id": "dexar",
    "name": "dexar",
    "displayName": "Dexar Marketplace",
    "active": true,
    "logoUrl": "https://..."
  }
]

Категории

Получить категории проекта

GET /api/projects/:projectId/categories

Ответ 200:
[
  {
    "id": "cat1",
    "name": "Электроника",
    "visible": true,
    "priority": 1,
    "img": "https://...",
    "projectId": "dexar",
    "subcategories": [ ...Subcategory[] ],
    "translations": {
      "ru": { "name": "Электроника" }
    }
  }
]

Получить категорию по ID

GET /api/categories/:categoryId

Ответ 200: (объект категории с вложенными подкатегориями)

Создать категорию

POST /api/projects/:projectId/categories

Тело запроса:
{
  "name": "Новая категория",     // обязательно
  "visible": true,
  "priority": 10,
  "img": "https://...",
  "translations": {              // опционально
    "ru": { "name": "Новая категория" }
  }
}

Ответ 201: (созданный объект категории)

Обновить категорию

PATCH /api/categories/:categoryId

Тело запроса: (любое подмножество полей)
{
  "name": "Обновлённое название",
  "visible": false,
  "priority": 5,
  "translations": {
    "ru": { "name": "Обновлённое название" }
  }
}

Ответ 200: (обновлённый объект категории)

Удалить категорию

DELETE /api/categories/:categoryId

Ответ 204 No Content

Примечание: каскадно удаляет все подкатегории и товары внутри

Подкатегории

Подкатегории рекурсивны — вложенность неограничена. Единственное ограничение: подкатегория с товарами не может иметь дочерних подкатегорий (и наоборот).

Объект подкатегории

{
  "id": "sub1",
  "name": "Смартфоны",
  "visible": true,
  "priority": 1,
  "img": "https://...",
  "categoryId": "cat1",        // всегда ID корневой категории
  "parentId": "cat1",          // ID прямого родителя (категория или подкатегория)
  "itemCount": 15,
  "hasItems": true,
  "subcategories": [],         // дочерние подкатегории (пусто, если hasItems = true)
  "translations": {
    "ru": { "name": "Смартфоны" }
  }
}

categoryId — всегда ID корневой категории этого поддерева.
parentId — ID прямого родителя: может быть ID категории или подкатегории.


Получить подкатегории категории

GET /api/categories/:categoryId/subcategories

Ответ 200: Subcategory[] (вложенные подкатегории рекурсивно заполнены)

Получить подкатегорию по ID

GET /api/subcategories/:subcategoryId

Ответ 200: объект подкатегории (с вложенными подкатегориями при наличии)

Создать подкатегорию в категории (уровень 1)

POST /api/categories/:categoryId/subcategories

Тело запроса:
{
  "id": "custom-id",        // опционально, генерируется автоматически (используется в URL)
  "name": "Смартфоны",      // обязательно
  "visible": true,
  "priority": 10,
  "translations": {
    "ru": { "name": "Смартфоны" }
  }
}

Ответ 201: (созданный объект подкатегории)
Ошибка 400: если категория не существует

Создать подкатегорию в подкатегории (уровень 2+, вложенная)

POST /api/subcategories/:parentSubcategoryId/subcategories

Тело запроса:
{
  "id": "custom-id",    // опционально
  "name": "Apple",      // обязательно
  "visible": true,
  "priority": 10
}

Ответ 201: (созданный объект подкатегории)
Ошибка 400: если родительская подкатегория содержит товары (hasItems = true)
Ошибка 404: если родительская подкатегория не найдена

Обновить подкатегорию

PATCH /api/subcategories/:subcategoryId

Тело запроса: (любое подмножество полей)
{
  "id": "new-slug",         // ID редактируется — используется в URL маркетплейса
  "name": "Новое название",
  "visible": false,
  "priority": 3,
  "translations": {
    "ru": { "name": "Новое название" }
  }
}

Ответ 200: (обновлённый объект подкатегории)

Удалить подкатегорию

DELETE /api/subcategories/:subcategoryId

Ответ 204 No Content

Примечание: каскадно удаляет все вложенные подкатегории и товары

Товары

Товары всегда принадлежат самой глубокой подкатегории в иерархии (листовой узел). Подкатегория с хотя бы одним товаром имеет hasItems: true и не может принимать дочерние подкатегории.

Получить товары (с пагинацией)

GET /api/subcategories/:subcategoryId/items

Query-параметры:
  page     number   (по умолчанию: 1)
  limit    number   (по умолчанию: 20)
  search   string   опционально — фильтр по названию (без учёта регистра)
  visible  boolean  опционально — фильтр по видимости
  tags     string   опционально — теги через запятую
  lang     string   опционально — код языка (en | ru); влияет на поля names/descriptions в ответе

Ответ 200:
{
  "items": [
    {
      "id": "item1",
      "name": "iPhone 15 Pro",
      "visible": true,
      "priority": 1,
      "quantity": 50,
      "price": 1299,
      "discount": 10,
      "currency": "USD",
      "imgs": ["https://...", "https://..."],
      "tags": ["new", "featured"],
      "badges": ["new", "exclusive"],
      "simpleDescription": "Последний iPhone...",
      "description": [
        { "key": "Цвет", "value": "Чёрный" },
        { "key": "Память", "value": "256 ГБ" }
      ],
      "subcategoryId": "sub1",
      "translations": {
        "ru": {
          "name": "iPhone 15 Pro",
          "simpleDescription": "Последний iPhone с корпусом из титана",
          "description": [
            { "key": "Цвет", "value": "Чёрный" },
            { "key": "Память", "value": "256 ГБ" }
          ]
        }
      },
      "comments": [
        {
          "id": "c1",
          "text": "Отличный товар!",
          "author": "Иван",
          "stars": 5,
          "createdAt": "2024-01-10T10:30:00Z"
        }
      ]
    }
  ],
  "total": 150,
  "page": 1,
  "limit": 20,
  "hasMore": true
}

Получить товар по ID

GET /api/items/:itemId

Query-параметры:
  lang  string  опционально (en | ru)

Ответ 200: (полный объект товара)

Создать товар

POST /api/subcategories/:subcategoryId/items

Тело запроса:
{
  "name": "Новый товар",              // обязательно
  "visible": true,
  "priority": 10,
  "quantity": 100,
  "price": 999,
  "discount": 0,                  // 0100 (процент скидки)
  "currency": "USD",                  // USD | EUR | RUB | GBP | UAH
  "imgs": ["https://..."],
  "tags": ["new"],
  "badges": ["new", "exclusive"],     // опционально — стандартные или свои метки
  "simpleDescription": "Краткое описание",
  "description": [
    { "key": "Размер", "value": "Большой" }
  ],
  "translations": {                   // опционально
    "ru": {
      "name": "Новый товар",
      "simpleDescription": "Краткое описание",
      "description": [
        { "key": "Размер", "value": "Большой" }
      ]
    }
  }
}

Ответ 201: (созданный объект товара)

Побочный эффект: устанавливает hasItems = true на подкатегории.
                 Подкатегория больше не может принимать дочерние подкатегории.

Обновить товар

PATCH /api/items/:itemId

Тело запроса: (любое подмножество полей)
{
  "name": "Новое название",
  "price": 899,
  "discount": 15,
  "quantity": 80,
  "visible": false,
  "translations": {
    "ru": { "name": "Новое название" }
  }
}

Ответ 200: (обновлённый объект товара)

Обновление изображений — всегда передавай полный массив:

PATCH /api/items/:itemId

Тело запроса:
{
  "imgs": ["https://new1.jpg", "https://new2.jpg"]
}

Ответ 200: (обновлённый объект товара)

Удалить товар

DELETE /api/items/:itemId

Ответ 204 No Content

Побочный эффект: если в подкатегории не осталось товаров — hasItems становится false.
                 Подкатегория снова может принимать дочерние подкатегории.

Массовое обновление товаров

PATCH /api/items/bulk

Тело запроса:
{
  "itemIds": ["item1", "item2", "item3"],
  "data": {
    "visible": true
  }
}

Ответ 204 No Content

Загрузка файлов

Загрузить изображение

POST /api/upload

Тело запроса: multipart/form-data
  image: File

Ответ 201:
{
  "url": "https://cdn.example.com/uploads/abc123.jpg"
}

Мультиязычность (i18n)

Поля name, simpleDescription и description поддерживают переводы через объект translations.

Структура объекта переводов

{
  "translations": {
    "ru": {
      "name": "Название на русском",
      "simpleDescription": "Описание на русском",
      "description": [
        { "key": "Ключ", "value": "Значение" }
      ]
    }
  }
}

Основные поля (name, simpleDescription, description) хранятся на английском (по умолчанию).
Переводы хранятся в translations[langCode].*.

Запрос конкретного языка

Передай параметр ?lang=ru в GET-запросах. Бэкенд должен:

  1. Вернуть translations.ru.* там, где перевод заполнен.
  2. Откатиться к основному полю (английскому), если перевод отсутствует.
GET /api/items/:itemId?lang=ru
GET /api/subcategories/:subcategoryId/items?lang=ru&page=1

Альтернативно — заголовок Accept-Language: ru.

Поддерживаемые языки

Код Язык
en Английский (по умолчанию)
ru Русский

Примечания

  • Все ответы — JSON.
  • Используй PATCH для частичного обновления — передавай только изменяемые поля.
  • priority: меньшее число — выше в списке.
  • Поддерживаемые значения currency: USD, EUR, RUB, GBP, UAH.
  • badges: необязательный массив строк. Стандартные значения с цветами в интерфейсе: new, sale, exclusive, hot, limited, bestseller, featured. Свои строки тоже допустимы.
  • imgs: при обновлении всегда передавай полный массив, не отдельные изображения.
  • discount: целое число 0100 — процент скидки. 0 означает отсутствие скидки. Цена со скидкой вычисляется как price * (1 - discount / 100).
  • description: массив пар { key, value } — свободные атрибуты товара.
  • Автосохранение из бэкофиса отправляет PATCH с одним полем каждые ~500 мс.

Бизнес-правила

Вложенные подкатегории

Иерархия выглядит так:

Категория (напр. Электроника)
  Подкатегория L1 (напр. Кухня)         <- можно добавлять детей ИЛИ товары, не оба
    Подкатегория L2 (напр. Большая кухня) <- то же правило
      Подкатегория L3 (напр. Духовки)    <- если есть товары — это листовой узел
        Товары...

Правила:

  • Категория всегда может принимать новые подкатегории (категории никогда не хранят товары напрямую).
  • Подкатегория с товарами (hasItems: true) не может принимать дочерние подкатегории.
    • POST /api/subcategories/:id/subcategories на узел с hasItems: true400 Bad Request.
  • Подкатегория с дочерними подкатегориями не может принимать товары (товары только в листовых узлах).
  • При создании первого товара в подкатегории → hasItems становится true.
  • При удалении последнего товараhasItems становится false; дочерние подкатегории снова можно добавлять.

Структура URL (фронтенд маркетплейса)

Поля id подкатегорий и товаров используются напрямую в URL маркетплейса:

/{categoryId}/{sub1Id}/{sub2Id}/.../{itemId}

Примеры:
  /electronics/smartphones/iphone-15
  /electronics/smartphones/apple/iphone-15-pro
  /furniture/living-room/sofas/corner-sofa-modelo

Поле id подкатегорий редактируется через PATCH для переименования слагов.

Комментарии

  • stars — опционально, целое число от 1 до 5.
  • author — опционально (анонимные комментарии допустимы).
  • createdAt — строка в формате ISO 8601.

Каскадное удаление

Удаляемый объект Также удаляется
Категория все подкатегории (рекурсивно) и их товары
Подкатегория все вложенные подкатегории (рекурсивно) и их товары
Товар ничего больше