Менеджер ресурсов (ResourceManager)

Функция управления ресурсами в NocoBase автоматически преобразует существующие коллекции и связи в ресурсы, а встроенные типы операций помогают разработчикам быстро строить REST API-операции над ресурсами. В отличие от традиционных REST API, операции с ресурсами в NocoBase не зависят от HTTP-метода запроса, а определяются через явное указание :action.

Автогенерация ресурсов

NocoBase автоматически преобразует collection и association, определенные в базе данных, в ресурсы. Например, если определить две коллекции — posts и tags:

db.defineCollection({
  name: 'posts',
  fields: [
    { type: 'belongsToMany', name: 'tags' },
  ],
});

db.defineCollection({
  name: 'tags',
  fields: [],
});

Будут автоматически созданы следующие ресурсы:

  • ресурс posts
  • ресурс tags
  • ресурс ассоциации posts.tags

Примеры запросов:

МетодПутьОперация
GET/api/posts:listЗапрос списка
GET/api/posts:get/1Запрос записи
POST/api/posts:createДобавление
POST/api/posts:update/1Обновление
POST/api/posts:destroy/1Удаление
МетодПутьОперация
GET/api/tags:listЗапрос списка
GET/api/tags:get/1Запрос записи
POST/api/tags:createДобавление
POST/api/tags:update/1Обновление
POST/api/tags:destroy/1Удаление
МетодПутьОперация
GET/api/posts/1/tags:listЗапрос всех tags, связанных с post
GET/api/posts/1/tags:get/1Запрос одного tag в рамках post
POST/api/posts/1/tags:createСоздание одного tag в рамках post
POST/api/posts/1/tags:update/1Обновление одного tag в рамках post
POST/api/posts/1/tags:destroy/1Удаление одного tag в рамках post
POST/api/posts/1/tags:addДобавление связанных tags для post
POST/api/posts/1/tags:removeУдаление связанных tags у post
POST/api/posts/1/tags:setУстановка полного набора связанных tags для post
POST/api/posts/1/tags:toggleПереключение связей tags для post
Подсказка

Операции ресурсов в NocoBase напрямую не зависят от метода запроса; операция определяется через явный :action.

Операции ресурса

NocoBase предоставляет широкий набор встроенных типов операций для разных бизнес-сценариев.

Базовые CRUD-операции

Имя операцииОписаниеПрименимые типы ресурсовМетод запросаПример пути
listЗапрос списка данныхВсеGET/POST/api/posts:list
getЗапрос одной записиВсеGET/POST/api/posts:get/1
createСоздание новой записиВсеPOST/api/posts:create
updateОбновление записиВсеPOST/api/posts:update/1
destroyУдаление записиВсеPOST/api/posts:destroy/1
firstOrCreateНайти первую запись, иначе создатьВсеPOST/api/users:firstOrCreate
updateOrCreateОбновить запись, иначе создатьВсеPOST/api/users:updateOrCreate

Операции со связями

Имя операцииОписаниеПрименимые типы связейПример пути
addДобавить связьhasMany, belongsToMany/api/posts/1/tags:add
removeУдалить связьhasOne, hasMany, belongsToMany, belongsTo/api/posts/1/comments:remove
setПереустановить связьhasOne, hasMany, belongsToMany, belongsTo/api/posts/1/comments:set
toggleДобавить или снять связьbelongsToMany/api/posts/1/tags:toggle

Параметры операций

Общие параметры операций:

  • filter: условия запроса
  • values: устанавливаемые значения
  • fields: поля, которые нужно вернуть
  • appends: включение связанных данных
  • except: исключаемые поля
  • sort: правила сортировки
  • page, pageSize: параметры пагинации
  • paginate: включать ли пагинацию
  • tree: возвращать ли древовидную структуру
  • whitelist, blacklist: белый/черный список полей
  • updateAssociationValues: обновлять ли значения связей

Пользовательские операции ресурсов

NocoBase позволяет регистрировать дополнительные операции для существующих ресурсов. С помощью registerActionHandlers можно настраивать операции как для всех ресурсов, так и для конкретных.

Регистрация глобальных операций

resourceManager.registerActionHandlers({
  customAction: async (ctx) => {
    ctx.body = { resource: ctx.action.resourceName };
  },
});

Регистрация операций для конкретного ресурса

resourceManager.registerActionHandlers({
  'posts:publish': async (ctx) => publishPost(ctx),
  'posts.comments:pin': async (ctx) => pinComment(ctx),
});

Примеры запросов:

POST /api/posts:customAction
POST /api/posts:publish
POST /api/posts/1/comments:pin

Правило именования: resourceName:actionName; при работе со связями используйте точечную нотацию (posts.comments).

Пользовательские ресурсы

Если нужно предоставить ресурсы, не связанные с коллекциями, используйте метод resourceManager.define:

resourceManager.define({
  name: 'app',
  actions: {
    getInfo: async (ctx) => {
      ctx.body = { version: 'v1' };
    },
  },
});

Методы запроса согласованы с автосгенерированными ресурсами:

  • GET /api/app:getInfo
  • POST /api/app:getInfo (по умолчанию поддерживаются оба: GET/POST)

Пользовательское промежуточное ПО

Используйте метод resourceManager.use() для регистрации глобального промежуточного ПО. Например:

Глобальное промежуточное ПО для логирования

resourceManager.use(async (ctx, next) => {
  const start = Date.now();
  await next();
  const duration = Date.now() - start;
  console.log(`${ctx.method} ${ctx.path} - ${duration}ms`);
});

Специальные свойства контекста

Если запрос дошел до промежуточного ПО или операции на уровне resourceManager, значит соответствующий ресурс уже существует.

ctx.action

  • ctx.action.actionName: имя операции
  • ctx.action.resourceName: может быть коллекцией или ассоциацией
  • ctx.action.params: параметры операции

ctx.dataSource

Текущий объект источника данных.

ctx.getCurrentRepository()

Текущий объект репозитория.

Как получить объект resourceManager для разных источников данных

resourceManager принадлежит источнику данных, и операции можно регистрировать отдельно для каждого источника.

Основной источник данных

Для основного источника данных можно напрямую использовать app.resourceManager:

app.resourceManager.registerActionHandlers();

Другие источники данных

Для других источников данных можно получить конкретный экземпляр через dataSourceManager и использовать resourceManager этого экземпляра:

const dataSource = dataSourceManager.get('external');
dataSource.resourceManager.registerActionHandlers();

Обход всех источников данных

Если нужно выполнить одинаковые операции для всех добавленных источников данных, используйте метод dataSourceManager.afterAddDataSource для обхода. Это гарантирует, что в resourceManager каждого источника можно зарегистрировать соответствующие операции:

dataSourceManager.afterAddDataSource((dataSource) => {
  dataSource.resourceManager.registerActionHandlers();
});