strapi-utils
页面摘要:
@strapi/utils包提供 Strapi 核心内部使用的共享辅助函数,也可在你的自定义代码中使用。它包括错误类、环境变量辅助函数、钩子工厂、类型解析、字符串和文件工具,以及异步辅助函数。
@strapi/utils 包(import { ... } from '@strapi/utils')包含 Strapi 内部使用的工具函数,但你也可以在自定义的 控制器、服务、策略、中间件 和 生命周期钩子 中使用它们。
本页各章节按导出名称的字母顺序排列。使用右侧的目录直接跳转到你需要的工具。
async
async 命名空间提供异步工具函数。导入方式如下:
const { async } = require('@strapi/utils');
以下函数可用:
| 函数 | 描述 |
|---|---|
async.map(iterable, mapper, options?) | 使用 p-map 的并行 map。在 options 中设置 concurrency 以控制并发度。 |
async.pipe(...fns) | 组合函数:第一个函数使用原始参数运行,每个后续函数接收前一个返回值。返回 Promise。 |
async.reduce(array)(iteratee, initialValue?) | 对数组的异步 reduce。分 2 步调用:先传入数组,再传入 iteratee 和可选的初始值。iteratee 接收 (accumulator, item, index)。 |
以下示例使用 pipe 组合异步函数,并使用 reduce 累积值:
const { async: asyncUtils } = require('@strapi/utils');
// Compose async functions into a pipeline
const result = await asyncUtils.pipe(
fetchUser,
enrichWithProfile,
formatResponse
)(userId);
// Reduce an array asynchronously (note the curried call)
const total = await asyncUtils.reduce([1, 2, 3])(
async (sum, n) => sum + n,
0
); // 6
contentTypes
contentTypes 命名空间暴露用于处理 Strapi 内容类型模式的常量和辅助函数。导入方式如下:
const { contentTypes } = require('@strapi/utils');
Constants
以下常量可用:
| 常量 | 值 | 描述 |
|---|---|---|
ID_ATTRIBUTE | 'id' | 主键字段名 |
DOC_ID_ATTRIBUTE | 'documentId' | 文档标识符字段名 |
PUBLISHED_AT_ATTRIBUTE | 'publishedAt' | 发布时间戳字段名 |
FIRST_PUBLISHED_AT_ATTRIBUTE | 'firstPublishedAt' | 首次发布时间戳字段名 |
CREATED_BY_ATTRIBUTE | 'createdBy' | 创建者引用字段名 |
UPDATED_BY_ATTRIBUTE | 'updatedBy' | 最后编辑者引用字段名 |
CREATED_AT_ATTRIBUTE | 'createdAt' | 创建时间戳字段名 |
UPDATED_AT_ATTRIBUTE | 'updatedAt' | 更新时间戳字段名 |
SINGLE_TYPE | 'singleType' | 单一类型种类标识符 |
COLLECTION_TYPE | 'collectionType' | 集合类型种类标识符 |
Attribute inspection functions
以下函数检查单个属性的类型:
| 函数 | 描述 |
|---|---|
isComponentAttribute(attribute) | 检查属性是否为组件或动态区域(两者均返回 true;使用 isDynamicZoneAttribute 区分) |
isDynamicZoneAttribute(attribute) | 检查属性是否为动态区域 |
isMediaAttribute(attribute) | 检查属性是否为媒体字段 |
isMorphToRelationalAttribute(attribute) | 检查属性是否为 morph-to 关系 |
isRelationalAttribute(attribute) | 检查属性是否为关系 |
isScalarAttribute(attribute) | 检查属性是否为标量值 标量值是单个、独立的值,而非集合或结构。在 Strapi 中,这意味着像字符串、数字、布尔值或日期这样的基础字段——不是关系、组件或嵌套对象。 |
isTypedAttribute(attribute, type) | 检查属性是否具有特定类型 |
Schema inspection functions
以下函数检查整个内容类型模式:
| 函数 | 描述 |
|---|---|
getCreatorFields(schema) | 返回模式中存在的创建者字段(createdBy、updatedBy) |
getNonWritableAttributes(schema) | 返回不可写入的字段名 |
getScalarAttributes(schema) | 返回标量值属性 |
getTimestamps(schema) | 返回模式中存在的时间戳字段(createdAt、updatedAt) |
getVisibleAttributes(schema) | 返回未被标记为非可见的模式属性 |
getWritableAttributes(schema) | 返回可写入的字段名 |
hasDraftAndPublish(schema) | 检查模式是否启用了草稿与发布 |
isWritableAttribute(schema, attributeName) | 检查特定属性是否可写 |
以下示例遍历内容类型的属性以查找关系和可写字段:
const { contentTypes } = require('@strapi/utils');
const articleSchema = strapi.contentType('api::article.article');
// List all relation fields
for (const [name, attribute] of Object.entries(articleSchema.attributes)) {
if (contentTypes.isRelationalAttribute(attribute)) {
console.log(`${name} is a relation`);
}
}
// Get only the fields that can be written to
const writableFields = contentTypes.getWritableAttributes(articleSchema);
// Check if draft and publish is enabled
if (contentTypes.hasDraftAndPublish(articleSchema)) {
console.log('This content type supports drafts');
}
env
一个用于以类型安全方式解析读取环境变量的辅助函数。env 函数返回原始字符串值,而其方法将值解析为特定类型。导入方式如下:
const { env } = require('@strapi/utils');
// or in TypeScript: import { env } from '@strapi/utils';
env 辅助函数可直接调用,也可使用以下类型化方法:
| 方法 | 返回类型 | 描述 |
|---|---|---|
env(key) | string \| undefined | 返回原始值 |
env(key, default) | string | 返回原始值或默认值 |
env.array(key, default?) | string[] \| undefined | 按逗号分割,修剪值,去除周围的 [] 和双引号 |
env.bool(key, default?) | boolean \| undefined | 'true' 返回 true,其他值返回 false |
env.date(key, default?) | Date \| undefined | 使用 new Date() 解析 |
env.float(key, default?) | number \| undefined | 解析为浮点数(parseFloat) |
env.int(key, default?) | number \| undefined | 解析为整数(parseInt) |
env.json(key, default?) | object \| undefined | 解析为 JSON;在 JSON 无效时抛出带有描述性消息的 Error |
env.oneOf(key, expectedValues, default?) | string \| undefined | 仅当值匹配 expectedValues 之一时才返回值,否则返回 default。如果未提供 expectedValues 或 default 本身不在 expectedValues 中则抛出错误。 |
以下示例展示了如何在服务器配置文件中使用 env 辅助函数:
const { env } = require('@strapi/utils');
module.exports = {
host: env('HOST', '0.0.0.0'),
port: env.int('PORT', 1337),
app: {
keys: env.array('APP_KEYS'),
},
};
errors
扩展 Node.js Error 类的自定义错误类。所有错误共享一个通用结构:
| 属性 | 类型 | 描述 |
|---|---|---|
name | string | 错误类名(例如 'ApplicationError'、'ValidationError') |
message | string | 人类可读的错误消息 |
details | object | 附加错误上下文 |
错误类导入方式如下:
const { errors } = require('@strapi/utils');
// or in TypeScript: import { errors } from '@strapi/utils';
以下错误类可用:
| 错误类 | 默认消息 | 详情默认值 |
|---|---|---|
ApplicationError | 'An application error occurred' | {} |
ValidationError | (必填) | 取决于构造函数输入 |
YupValidationError | 'Validation'(或格式化后的 Yup 消息) | { errors: [] } |
PaginationError | 'Invalid pagination' | 取决于构造函数输入 |
NotFoundError | 'Entity not found' | 取决于构造函数输入 |
ForbiddenError | 'Forbidden access' | 取决于构造函数输入 |
UnauthorizedError | 'Unauthorized' | 取决于构造函数输入 |
RateLimitError | 'Too many requests, please try again later.' | {} |
PayloadTooLargeError | 'Entity too large' | 取决于构造函数输入 |
PolicyError | 'Policy Failed' | {} |
NotImplementedError | 'This feature is not implemented yet' | 取决于构造函数输入 |
PolicyError 扩展自 ForbiddenError。所有其他错误类都扩展自 ApplicationError。
以下示例展示了如何在服务中以及在策略中抛出异常:
const { errors } = require('@strapi/utils');
// In a service or lifecycle hook
throw new errors.ApplicationError('Something went wrong', { foo: 'bar' });
// In a policy
throw new errors.PolicyError('Access denied', { policy: 'is-owner' });
在模型生命周期钩子中抛出异常时使用 ApplicationError,以便在管理面板中显示有意义的消息。更多示例请参阅 错误处理 页面。
file
file 命名空间提供用于处理流和文件大小的辅助函数。导入方式如下:
const { file } = require('@strapi/utils');
以下函数可用:
| 函数 | 返回类型 | 描述 |
|---|---|---|
bytesToHumanReadable(bytes) | string | 将字节格式化为人类可读的字符串(例如 '2 MB') |
bytesToKbytes(bytes) | number | 将字节转换为千字节(四舍五入到 2 位小数) |
getStreamSize(stream) | Promise<number> | 计算流的总大小(以字节为单位) |
kbytesToBytes(kbytes) | number | 将千字节转换为字节 |
streamToBuffer(stream) | Promise<Buffer> | 将可读流转换为 Buffer |
writableDiscardStream(options?) | Writable | 创建一个丢弃所有数据的可写流 |
以下示例将上传的流转换为 buffer 并记录其大小:
const { file } = require('@strapi/utils');
const buffer = await file.streamToBuffer(uploadStream);
const sizeInKb = file.bytesToKbytes(buffer.length);
console.log(`Uploaded ${file.bytesToHumanReadable(buffer.length)} (${sizeInKb} KB)`);
hooks
用于创建钩子注册表的工厂函数。钩子允许你注册处理函数并以不同模式执行它们。命名空间导入方式如下:
const { hooks } = require('@strapi/utils');
每个钩子实例暴露以下 4 个方法:
| 方法 | 描述 |
|---|---|
register(handler) | 向钩子添加处理函数 |
delete(handler) | 移除之前注册的处理函数 |
getHandlers() | 返回已注册处理函数的列表 |
call(...args) | 根据钩子类型执行已注册的处理函数 |
Available hook factories
以下工厂函数创建不同的钩子类型。当处理函数必须按顺序运行时使用 series(串行),当每个处理函数为下一个转换数据时使用 waterfall(瀑布),当处理函数相互独立且可并发运行时使用 parallel(并行),当你需要第一个返回值以短路其余处理函数时使用 bail(中断):
| 工厂 | 执行模式 |
|---|---|
hooks.createAsyncSeriesHook() | 使用相同上下文按顺序执行处理函数 |
hooks.createAsyncSeriesWaterfallHook() | 按顺序执行处理函数,将每个返回值传递给下一个处理函数 |
hooks.createAsyncParallelHook() | 并发执行所有处理函数 |
hooks.createAsyncBailHook() | 按顺序执行处理函数,在第一个返回非 undefined 值的处理函数处停止 |
以下示例使用 series hook(串行钩子)注册并调用处理函数 串行钩子按顺序逐一执行处理函数,按照它们注册的顺序。其他模式包括 waterfall(每个处理函数接收前一个处理函数的返回值)、parallel(所有处理函数并发运行)和 bail(在第一个返回值的处理函数处停止)。更多详情请参阅 admin hooks。:
const { hooks } = require('@strapi/utils');
const myHook = hooks.createAsyncSeriesHook();
myHook.register(async (context) => {
console.log('First handler', context);
});
myHook.register(async (context) => {
console.log('Second handler', context);
});
// Execute all handlers in order
await myHook.call({ data: 'example' });
pagination
pagination 命名空间提供用于处理分页参数的辅助函数。导入方式如下:
const { pagination } = require('@strapi/utils');
以下函数可用:
| 函数 | 描述 |
|---|---|
transformOffsetPaginationInfo(params, total) | 将分页数据转换为 { start, limit, total } 格式 |
transformPagedPaginationInfo(params, total) | 将分页数据转换为 { page, pageSize, pageCount, total } 格式 |
withDefaultPagination(params, options?) | 应用默认值并验证分页参数(详见下文) |
withDefaultPagination 函数同时支持 page/pageSize 和 start/limit 格式。它接受一个可选的 options 对象,具有以下属性:
| 选项 | 类型 | 描述 |
|---|---|---|
defaults | object | 覆盖每种格式的初始分页值(例如 { page: { pageSize: 25 } }) |
maxLimit | number | 限制 limit 或 pageSize 的值。设为 -1 表示不限制。 |
以下示例应用默认分页并转换结果:
const { pagination } = require('@strapi/utils');
const params = pagination.withDefaultPagination({ page: 2 }, { maxLimit: 100 });
const info = pagination.transformPagedPaginationInfo(params, 250);
// { page: 2, pageSize: 25, pageCount: 10, total: 250 }
parseType
将值转换为特定的 Strapi 字段类型。函数导入方式如下:
const { parseType } = require('@strapi/utils');
函数接受以下参数:
| 参数 | 类型 | 描述 |
|---|---|---|
type | string | 目标类型:'boolean'、'integer'、'biginteger'、'float'、'decimal'、'time'、'date'、'timestamp' 或 'datetime' |
value | unknown | 要解析的值 |
forceCast | boolean | 强制转换布尔值。默认值:false |
返回值取决于目标类型:
| 类型 | 返回类型 | 格式 |
|---|---|---|
boolean | boolean | 接受 'true'、't'、'1'、1 作为 true |
integer, biginteger, float, decimal | number | 数值转换 |
time | string | HH:mm:ss.SSS |
date | string | yyyy-MM-dd |
timestamp, datetime | Date | Date 对象 |
以下示例演示了解析不同的字段类型:
parseType({ type: 'boolean', value: 'true' }); // true
parseType({ type: 'integer', value: '42' }); // 42
parseType({ type: 'date', value: '2024-01-15T10:30:00Z' }); // '2024-01-15'
policy
用于创建和管理 策略 的辅助函数。该命名空间暴露 2 个函数:createPolicy 用于定义带有可选配置验证器的策略处理函数,createPolicyContext 用于构建处理函数可检查的带类型上下文对象。命名空间导入方式如下:
const { policy } = require('@strapi/utils');
createPolicy
创建一个带有可选配置验证器的策略。函数接受以下参数:
| 参数 | 类型 | 必填 | 描述 |
|---|---|---|---|
name | string | 否 | 策略名称(默认为 'unnamed') |
handler | function | 是 | 策略处理函数 |
validator | function | 否 | 验证策略配置;配置无效时抛出 |
以下示例创建了一个带有配置验证器的策略:
const myPolicy = policy.createPolicy({
name: 'is-owner',
validator: (config) => {
if (!config.field) throw new Error('Missing field');
},
handler: (ctx, config, { strapi }) => {
// policy logic
return true;
},
});
createPolicyContext
createPolicyContext 函数创建一个带类型的上下文对象,供策略处理函数内部使用。它接受一个类型字符串(例如 'admin' 或 'koa')和 Koa 上下文,并返回一个带有 is() 方法和 type 属性的对象:
const policyCtx = policy.createPolicyContext('admin', ctx);
policyCtx.is('admin'); // true
policyCtx.type; // 'admin'
primitives
底层数据转换辅助函数。以下子模块可作为来自 @strapi/utils 的直接顶层导入使用:
const { strings, objects, arrays, dates } = require('@strapi/utils');
strings
以下字符串工具函数可用:
| 函数 | 描述 |
|---|---|
strings.getCommonPath(...paths) | 从多个文件路径中查找公共路径前缀 |
strings.isCamelCase(value) | 检查字符串是否为 camelCase 格式 |
strings.isEqual(a, b) | 将两个值作为字符串进行比较 |
strings.isKebabCase(value) | 检查字符串是否为 kebab-case 格式 |
strings.joinBy(separator, ...parts) | 使用分隔符连接字符串,在连接点修剪重复的分隔符 |
strings.nameToCollectionName(name) | 将名称转换为 snake_case 集合名称 |
strings.nameToSlug(name, options?) | 将名称转换为对 URL 友好的 slug。默认分隔符:'-' |
strings.startsWithANumber(value) | 检查字符串是否以数字开头 |
strings.toKebabCase(value) | 将字符串转换为 kebab-case |
strings.toRegressedEnumValue(value) | 将重音字符替换为其 ASCII 等价字符,然后用下划线分隔单词,生成适合用作枚举键的字符串(保留原始大小写) |
objects
以下对象工具函数可用:
| 函数 | 描述 |
|---|---|
objects.keysDeep(obj) | 以点表示法返回所有嵌套键(例如 ['a.b', 'a.c']) |
arrays
以下数组工具函数可用:
| 函数 | 描述 |
|---|---|
arrays.includesString(arr, val) | 当两者都作为字符串比较时,检查数组是否包含某个值 |
dates
以下日期工具函数可用:
| 函数 | 描述 |
|---|---|
dates.timestampCode(date?) | 将 Date(默认为 new Date())转换为毫秒时间戳的 36 进制字符串 |
providerFactory
创建一个可插拔的注册表,按键存储和检索项目,并带有生命周期钩子。这与 Strapi 内部用于其上传和邮件提供方的工厂相同。当你在自己的插件中需要可互换策略或适配器的存储时,使用 providerFactory。工厂导入方式如下:
const { providerFactory } = require('@strapi/utils');
Parameters
工厂接受以下参数:
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
throwOnDuplicates | boolean | true | 注册已存在的键时抛出错误 |
Provider methods
返回的提供方实例暴露以下方法:
| 方法 | 返回类型 | 描述 |
|---|---|---|
register(key, item) | Promise<Provider> | 注册一个项目。触发 willRegister 和 didRegister hooks。 |
delete(key) | Promise<Provider> | 移除一个项目。触发 willDelete 和 didDelete hooks。 |
get(key) | T \| undefined | 按键检索项目 |
values() | T[] | 返回所有已注册的项目 |
keys() | string[] | 返回所有已注册的键 |
has(key) | boolean | 检查键是否已注册 |
size() | number | 返回已注册项目的数量 |
clear() | Promise<Provider> | 移除所有项目 |
Provider hooks
每个提供方实例暴露一个 hooks 对象,包含 4 个钩子注册表:
| 钩子 | 类型 | 触发时机 |
|---|---|---|
hooks.willRegister | Async series | 在注册项目之前 |
hooks.didRegister | Async parallel | 在注册项目之后 |
hooks.willDelete | Async parallel | 在删除项目之前 |
hooks.didDelete | Async parallel | 在删除项目之后 |
以下示例创建一个提供方,并使用生命周期钩子注册一个项目:
const { providerFactory } = require('@strapi/utils');
const registry = providerFactory();
registry.hooks.willRegister.register(async ({ key, value }) => {
console.log(`About to register: ${key}`);
});
await registry.register('my-provider', { execute: () => {} });
registry.get('my-provider'); // { execute: [Function] }
registry.has('my-provider'); // true
registry.size(); // 1
relations
relations 命名空间提供用于检查关系属性基数(例如一对多 vs 多对多)的辅助函数。要检查某个属性是否为关系,请改用 contentTypes.isRelationalAttribute。命名空间导入方式如下:
const { relations } = require('@strapi/utils');
以下函数可用:
| 函数 | 描述 |
|---|---|
getRelationalFields(contentType) | 返回内容类型中的所有关系字段名 |
isAnyToMany(attribute) | 检查 oneToMany 或 manyToMany 关系 |
isAnyToOne(attribute) | 检查 oneToOne 或 manyToOne 关系 |
isManyToAny(attribute) | 检查 manyToMany 或 manyToOne 关系 |
isOneToAny(attribute) | 检查 oneToOne 或 oneToMany 关系 |
isPolymorphic(attribute) | 检查 morphOne、morphMany、morphToOne 或 morphToMany 关系 |
以下示例过滤内容类型的属性以查找所有一对多或多对多关系:
const { relations, contentTypes } = require('@strapi/utils');
const schema = strapi.contentType('api::article.article');
for (const [name, attribute] of Object.entries(schema.attributes)) {
if (contentTypes.isRelationalAttribute(attribute) && relations.isAnyToMany(attribute)) {
console.log(`${name} is a *-to-many relation`);
}
}
sanitize
sanitize 命名空间提供基于内容类型模式清理输入和输出数据的函数。在处理或返回数据之前,使用 sanitize 移除不允许的、私有的或受限的字段。
在大多数控制器中,你不需要直接调用 sanitize。Strapi 提供了内置的 sanitizeQuery 和 sanitizeOutput 辅助函数为你处理设置(详见 控制器 文档)。当你需要在控制器上下文之外(例如在服务或自定义脚本中)进行清理时,使用下面的底层 API。
命名空间导入方式如下:
const { sanitize } = require('@strapi/utils');
createAPISanitizers 函数接受一个模型解析器,并返回一组限定于该模型的清理器方法。模型解析器是一个函数,给定内容类型 UID(例如 'api::article.article'),返回相应的模式。实际上,strapi.getModel 已经做到了这一点。你通常在 bootstrap 期间或服务顶部调用一次 createAPISanitizers:
const sanitizers = sanitize.createAPISanitizers({
getModel: strapi.getModel.bind(strapi),
});
返回的对象提供以下内容:
| 方法 | 描述 |
|---|---|
sanitizers.input(data, schema, options?) | 清理请求体数据 |
sanitizers.output(data, schema, options?) | 清理响应数据 |
sanitizers.query(query, schema, options?) | 清理查询参数 |
sanitizers.filters(filters, schema, options?) | 清理过滤表达式 |
sanitizers.sort(sort, schema, options?) | 清理排序参数 |
sanitizers.fields(fields, schema, options?) | 清理字段选择 |
sanitizers.populate(populate, schema, options?) | 清理 populate 指令 |
每个方法接受一个可选的 options 对象,具有以下属性:
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
auth | object | undefined | 来自请求的鉴权对象(通常为 ctx.state.auth)。提供时,用户无权访问的关系字段将从输出中移除。省略时不进行基于权限的过滤。 |
strictParams | boolean | false | 为 true 时,移除未在内容类型模式中声明的字段或查询参数。为 false 时,未识别的字段直接通过。 |
route | object | undefined | 路由对象(通常为 ctx.route)。当 strictParams 为 true 时,清理器从路由配置的 request 键读取信息,以了解核心集之外允许哪些自定义查询或请求体参数。当 strictParams 为 false 时无效果。有关路由配置的详情,请参阅 路由。 |
setCreatorFields
在实体上设置 createdBy 和 updatedBy 字段。当你构建在 Strapi 默认 文档服务 之外创建或更新条目的自定义控制器或服务时,使用此函数。该函数返回一个柯里化函数 柯里化函数是一种不一次性接收所有参数的函数。相反,它为每一个参数返回一个新的函数。这让你可以先固定某些参数,稍后再传入其余参数。例如,setCreatorFields({ user }) 返回一个可复用的函数,你可以在任意实体数据上调用它。:先使用选项调用它,再使用实体数据调用它。导入方式如下:
const { setCreatorFields } = require('@strapi/utils');
函数接受以下参数:
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
user | { id: string \| number } | (必填) | 执行操作的用户 |
isEdition | boolean | false | 为 true 时,仅设置 updatedBy;为 false 时,同时设置 createdBy 和 updatedBy |
以下示例展示了如何在创建和更新时设置创建者字段:
const { setCreatorFields } = require('@strapi/utils');
const addCreator = setCreatorFields({ user: { id: 1 } });
const data = addCreator({ title: 'My Article' });
// { title: 'My Article', createdBy: 1, updatedBy: 1 }
const updateCreator = setCreatorFields({ user: { id: 2 }, isEdition: true });
const updated = updateCreator(data);
// { title: 'My Article', createdBy: 1, updatedBy: 2 }
validate
validate 命名空间提供用于根据内容类型模式检查输入和查询数据的函数。使用 validate 拒绝引用未知、私有或受限字段的请求。
与 sanitize 类似,控制器已经提供了内置的验证辅助函数(validateQuery、validateInput)。当你需要在控制器上下文之外进行验证时,使用下面的底层 API。
命名空间导入方式如下:
const { validate } = require('@strapi/utils');
createAPIValidators 函数接受一个模型解析器(详见 sanitize),并返回一组限定于该模型的验证器方法:
const validators = validate.createAPIValidators({
getModel: strapi.getModel.bind(strapi),
});
返回的对象提供以下内容:
| 方法 | 描述 |
|---|---|
validators.input(data, schema, options?) | 验证请求体数据 |
validators.query(query, schema, options?) | 验证查询参数 |
validators.filters(filters, schema, options?) | 验证过滤表达式 |
validators.sort(sort, schema, options?) | 验证排序参数 |
validators.fields(fields, schema, options?) | 验证字段选择 |
validators.populate(populate, schema, options?) | 验证 populate 指令 |
每个方法接受一个可选的 options 对象,其属性与 sanitize 选项 相同:auth 用于基于权限的检查,strictParams 用于拒绝未知字段,route 用于在严格模式下允许自定义路由参数。
以下示例在自定义服务中验证查询并捕获错误:
const { validate, errors } = require('@strapi/utils');
const validators = validate.createAPIValidators({
getModel: strapi.getModel.bind(strapi),
});
try {
await validators.query(ctx.query, 'api::article.article', {
auth: ctx.state.auth,
});
} catch (error) {
// error is a ValidationError with details about which fields failed
console.error(error.message, error.details);
}
yup
yup 命名空间重新导出了 Yup 验证库 并带有 Strapi 特定的扩展。导入方式如下:
const { yup } = require('@strapi/utils');
Additional Yup methods
Strapi 向 Yup 模式添加了以下方法:
| 方法 | 模式类型 | 描述 |
|---|---|---|
yup.strapiID() | Custom | 验证 Strapi ID(字符串或非负整数) |
.notNil() | Any | 确保值不是 undefined 或 null |
.notNull() | Any | 确保值不是 null |
.isFunction() | Mixed | 验证值为函数 |
.isCamelCase() | String | 验证 camelCase 格式 |
.isKebabCase() | String | 验证 kebab-case 格式 |
.onlyContainsFunctions() | Object | 验证对象中的所有值都是函数 |
.uniqueProperty(property, message) | Array | 验证特定属性在数组各项中唯一 |
Schema validation helpers
validateYupSchema 和 validateYupSchemaSync 是 @strapi/utils 的顶层导出,不属于 yup 命名空间:
const { validateYupSchema, validateYupSchemaSync } = require('@strapi/utils');
以下辅助函数可用:
| 函数 | 描述 |
|---|---|
validateYupSchema(schema, options?) | 为 Yup 模式返回一个异步验证器函数 (body, errorMessage?) => Promise。默认选项:{ strict: true, abortEarly: false }。 |
validateYupSchemaSync(schema, options?) | 为 Yup 模式返回一个同步验证器函数 (body, errorMessage?) => result。默认选项:{ strict: true, abortEarly: false }。 |
zod
Strapi 重新导出了来自 Zod 的 z 实例,并提供了一个 validateZod 辅助函数,将 Zod 模式包装为 Strapi 风格的验证器。Strapi 不会向 Zod 添加自定义方法。z 是标准的 Zod API。辅助函数导入方式如下:
const { validateZod, z } = require('@strapi/utils');
以下示例定义了一个模式,并使用 validateZod 创建了一个验证器函数。成功时,函数返回解析后的数据。失败时,它抛出 ValidationError(参见 errors),并附带哪些字段失败的详情:
const schema = z.object({
name: z.string().min(1),
age: z.number().positive(),
});
const validate = validateZod(schema);
const parsed = validate({ name: 'Alice', age: 30 }); // returns parsed data
validate({ name: '' }); // throws ValidationError