Bỏ qua, đến nội dung

@digiforce-nc/actions

Package@digiforce-nc/actions
Importimport { registerActions } from '@digiforce-nc/actions'

Tổng quan

@digiforce-nc/actions cung cấp bộ action handler mặc định cho các thao tác CRUD tiêu chuẩn. Khi Application khởi tạo, package này đăng ký tất cả action vào ResourceManager, cho phép mọi resource tự động có sẵn các thao tác list, get, create, update, destroy và nhiều action khác.

Mỗi action handler nhận context chứa ctx.db (Database), ctx.cache (Cache) và ctx.action (action metadata + params), rồi thực hiện thao tác tương ứng trên repository.

Không cần viết CRUD handler

Nhờ package này, khi bạn tạo một Collection mới, hệ thống tự động cung cấp đầy đủ REST API mà không cần viết code handler. Chỉ cần define collection → có ngay GET /api/posts:list, POST /api/posts:create, v.v.


Kiến trúc

registerActions(resourceManager)

Hàm khởi tạo, đăng ký tất cả built-in action handler vào ResourceManager:

typescript
import { registerActions } from '@digiforce-nc/actions';

// Thường được gọi trong Application constructor
registerActions(app.resourceManager);

Danh sách action đầy đủ

ActionHTTP MethodMô tảParams chính
listGETDanh sách phân trangfilter, sort, fields, appends, except, page, pageSize
getGETLấy một recordfilterByTk, fields, appends, except, filter
createPOSTTạo record mớivalues, whitelist, blacklist
updatePUTCập nhật recordfilterByTk, values, whitelist, blacklist, filter
destroyDELETEXoá recordfilterByTk, filter
addPOSTThêm associationvalues
removePOSTGỡ associationvalues
setPOSTĐặt association (thay thế)values
togglePOSTToggle associationvalues
movePOSTSắp xếp lại thứ tựsourceId, targetId, sortField, method
queryGETTruy vấn tổng hợpmeasures, dimensions, filter, orders
firstOrCreatePOSTTìm hoặc tạo mớifilterKeys, values
updateOrCreatePOSTUpsertfilterKeys, values

Chi tiết từng action

list - danh sách phân trang

GET /api/<resource>:list
GET /api/<resource>
ParamTypeMô tả
filterobjectĐiều kiện lọc. Hỗ trợ operator: $eq, $ne, $gt, $lt, $in, $like, $and, $or, ...
sortstring[]Sắp xếp. Ví dụ: ['createdAt'] (ASC), ['-createdAt'] (DESC).
fieldsstring[]Chỉ trả về các field được chỉ định.
appendsstring[]Eager load association. Ví dụ: ['author', 'tags'].
exceptstring[]Loại trừ field.
pagenumberTrang hiện tại (mặc định: 1).
pageSizenumberSố record mỗi trang (mặc định: 20).

Response trả về:

json
{
  "data": [ { "id": 1, "title": "..." }, ... ],
  "meta": { "count": 100, "page": 1, "pageSize": 20, "totalPage": 5 }
}

get - lấy một record

GET /api/<resource>:get?filterByTk=1
GET /api/<resource>/1
ParamTypeMô tả
filterByTkstring | numberGiá trị target key (thường là id).
fieldsstring[]Chỉ trả về các field được chỉ định.
appendsstring[]Eager load association.
filterobjectĐiều kiện bổ sung (kết hợp AND với filterByTk).

create - tạo record mới

POST /api/<resource>:create
ParamTypeMô tả
valuesobjectDữ liệu tạo mới.
whiteliststring[]Chỉ cho phép các field trong whitelist được ghi.
blackliststring[]Cấm các field trong blacklist không được ghi.

whitelist vs blacklist

whitelistblacklist không thể dùng đồng thời. Nếu cả hai đều có, whitelist được ưu tiên.

update - cập nhật record

PUT /api/<resource>:update?filterByTk=1
PUT /api/<resource>/1
ParamTypeMô tả
filterByTkstring | numberTarget key của record cần cập nhật.
valuesobjectDữ liệu cập nhật (partial update).
whiteliststring[]Whitelist field được phép cập nhật.
blackliststring[]Blacklist field cấm cập nhật.
filterobjectĐiều kiện bổ sung - dùng cho batch update hoặc ACL filter.

destroy - xoá record

DELETE /api/<resource>:destroy?filterByTk=1
DELETE /api/<resource>/1
ParamTypeMô tả
filterByTkstring | numberTarget key. Có thể là array để xoá nhiều (filterByTk=[1,2,3]).
filterobjectĐiều kiện lọc - xoá tất cả record match filter.

Batch destroy

Khi truyền filter mà không có filterByTk, action sẽ xoá tất cả record match điều kiện. Luôn kiểm tra filter trước khi gọi.

add / remove / set / toggle - thao tác association

Dùng cho nested resource, ví dụ:

POST /api/posts/1/tags:add       - thêm tag vào post
POST /api/posts/1/tags:remove    - gỡ tag khỏi post
POST /api/posts/1/tags:set       - đặt lại toàn bộ tag
POST /api/posts/1/tags:toggle    - toggle (thêm nếu chưa có, gỡ nếu đã có)
ParamTypeMô tả
valuesnumber | number[]ID (hoặc array ID) của record association.

move - sắp xếp lại thứ tự

POST /api/<resource>:move
ParamTypeMô tả
sourceIdnumberID record cần di chuyển.
targetIdnumberID record đích (đặt trước/sau).
sortFieldstringTên field dùng để sort (mặc định: sort).
method'insertAfter' | 'insertBefore' | 'prepend'Phương thức di chuyển.

query - truy vấn tổng hợp

GET /api/<resource>:query
ParamTypeMô tả
measuresArray<{ field, aggregation }>Phép tính tổng hợp: count, sum, avg, min, max.
dimensionsArray<{ field, format? }>Field group by.
filterobjectĐiều kiện lọc.
ordersArray<{ field, order }>Sắp xếp kết quả.

firstOrCreate - tìm hoặc tạo mới

POST /api/<resource>:firstOrCreate
ParamTypeMô tả
filterKeysstring[]Các field dùng để tìm record tồn tại (ví dụ: ['email']).
valuesobjectDữ liệu tạo mới nếu không tìm thấy.

updateOrCreate - upsert

POST /api/<resource>:updateOrCreate
ParamTypeMô tả
filterKeysstring[]Các field dùng để tìm record.
valuesobjectDữ liệu tạo mới hoặc cập nhật.

Context type

Mỗi action handler nhận Koa Context đã được augment thêm các property:

typescript
interface ActionContext extends Context {
  db: Database;               // Database instance
  cache: Cache;               // Cache instance
  action: {
    actionName: string;       // Tên action (list, get, create, ...)
    resourceName: string;     // Tên resource (posts, users, ...)
    resourceOf: string;       // Parent resource (cho nested resource)
    params: ActionParams;     // Params đã merge
  };
}

Action params và mergeParams

Params trong action context được tổng hợp từ nhiều nguồn:

Chiến lược merge cho từng loại param:

ParamChiến lược merge
filterDeep merge với $and - tất cả filter đều được áp dụng
fieldsIntersection - chỉ giữ field có trong tất cả nguồn
appendsUnion - gộp tất cả
exceptUnion - gộp tất cả
sortGhi đè - nguồn sau ghi đè nguồn trước
page, pageSizeGhi đè
whitelistIntersection
blacklistUnion
valuesDeep merge

Ví dụ sử dụng

Đăng ký custom action

typescript
app.resourceManager.registerAction('posts:publish', async (ctx, next) => {
  const { filterByTk } = ctx.action.params;
  const repo = ctx.db.getRepository('posts');

  await repo.update({
    filterByTk,
    values: {
      status: 'published',
      publishedAt: new Date(),
    },
  });

  ctx.body = { success: true };
  await next();
});

Override built-in action

typescript
app.resourceManager.registerAction('posts:create', async (ctx, next) => {
  // Tự động gán author
  ctx.action.params.values = {
    ...ctx.action.params.values,
    authorId: ctx.state.currentUser.id,
  };

  // Gọi action mặc định
  const defaultCreate = require('@digiforce-nc/actions').create;
  await defaultCreate(ctx, next);
});

Sử dụng action với filter

typescript
// Client request: lấy danh sách posts đã publish, sắp xếp theo ngày tạo
const response = await api.resource('posts').list({
  filter: {
    status: 'published',
    createdAt: { $gt: '2024-01-01' },
  },
  sort: ['-createdAt'],
  fields: ['id', 'title', 'summary', 'createdAt'],
  appends: ['author'],
  page: 1,
  pageSize: 10,
});

Phụ thuộc

PackageVai trò
@digiforce-nc/cacheCaching layer cho action handler (query cache)
@digiforce-nc/databaseRepository/Model để thao tác dữ liệu
@digiforce-nc/resourcerResourceManager để đăng ký action handler

Đọc thêm