服务端 API:内容类型(Content-types)
页面摘要: 服务端 API 从服务端入口文件导出一个
contentTypes对象来声明插件内容类型。推荐的命名约定是让导出键与info.singularName使用相同的值,这样在查询或清理数据时运行时 UID 才能保持可预测。
一个插件可以通过从 服务端入口文件 导出 contentTypes 对象来声明自己的内容类型。Strapi 在启动时将这些内容类型注册到插件命名空间下,并通过文档服务 API 和内容类型注册表使它们可用。
在深入阅读本页概念之前,请确保你已经:
- 创建了一个 Strapi 插件,
- 阅读并理解了 Server API 的基础知识。
声明
contentTypes 导出是一个对象,其中每个键都在插件命名空间下注册一个内容类型。为避免混淆,该键应与 schema 中的 info.singularName 字段保持一致。其值是一个带有指向 schema 定义的 schema 属性的对象。
JavaScript
'use strict';
const article = require('./article');
module.exports = {
// highlight-next-line
article: { schema: article }, // recommended: keep key aligned with info.singularName
};
{
"kind": "collectionType",
"collectionName": "my_plugin_articles",
"info": {
// highlight-next-line
"singularName": "article",
"pluralName": "articles",
"displayName": "Article"
},
"options": {
"draftAndPublish": false
},
"attributes": {
"title": {
"type": "string",
"required": true
},
"body": {
"type": "richtext"
}
}
}
TypeScript
import article from './article';
export default {
// highlight-next-line
article: { schema: article }, // recommended: keep key aligned with info.singularName
};
{
"kind": "collectionType",
"collectionName": "my_plugin_articles",
"info": {
// highlight-next-line
"singularName": "article",
"pluralName": "articles",
"displayName": "Article"
},
"options": {
"draftAndPublish": false
},
"attributes": {
"title": {
"type": "string",
"required": true
},
"body": {
"type": "richtext"
}
}
}
UIDs 与命名约定
当一个插件内容类型被注册时,Strapi 会从插件命名空间和 contentTypes 导出中使用的键构建其运行时 UID:
plugin::<plugin-name>.<content-types-key>
推荐的约定是设置 content-types-key === info.singularName。遵循此约定可使 schema 命名与运行时 UID 保持一致,且更易阅读。
当键与 singularName 匹配时(推荐),生成的 UID 遵循以下格式:
plugin::<plugin-name>.<singular-name>
例如,一个名为 my-plugin 的插件,其内容类型的 singularName 为 article、导出键为 article,其 UID 为 plugin::my-plugin.article。
如果 contentTypes 键与 info.singularName 不一致,getters 和查询会使用从注册键(而非 singularName)构建的 UID。这可能会在插件代码中引入命名不一致。
此 UID 在所有 API 中一致使用:
| Use case | Example |
|---|---|
| 通过文档服务查询 | strapi.documents('plugin::my-plugin.article').findMany() |
| 通过 getter 访问 schema | strapi.contentType('plugin::my-plugin.article') |
| 在路由处理程序中引用 | handler: 'article.find'(简写形式,通过插件注册表解析) |
| 传递给清理 API | strapi.contentAPI.sanitize.output(data, schema, { auth }) |
控制器、服务、策略和中间件在全局 getters 中使用相同的 plugin::<plugin-name>.<resource-name> UID 格式,但在插件级 API(如路由 handler 和 policies)中通过简写注册表键(例如 'article')引用。详见 Getters & usage。
运行时访问
使用文档服务 API 查询
使用文档服务 API 从控制器、服务或生命周期 hook 中查询插件内容类型:
JavaScript
module.exports = ({ strapi }) => ({
async findAll(params = {}) {
// highlight-next-line
return strapi.documents('plugin::my-plugin.article').findMany(params);
},
async create(data) {
return strapi.documents('plugin::my-plugin.article').create({ data });
},
});
TypeScript
import type { Core } from '@strapi/strapi';
export default ({ strapi }: { strapi: Core.Strapi }) => ({
async findAll(params: Record<string, unknown> = {}) {
// highlight-next-line
return strapi.documents('plugin::my-plugin.article').findMany(params);
},
async create(data: Record<string, unknown>) {
return strapi.documents('plugin::my-plugin.article').create({ data });
},
});
有关可用方法和参数的完整列表,请参阅 文档服务 API。
访问 schema
使用内容类型 getter 来检索 schema 对象,例如将其传递给清理 API:
JavaScript
const schema = strapi.contentType('plugin::my-plugin.article');
const sanitizedOutput = await strapi.contentAPI.sanitize.output(
data,
schema,
{ auth: ctx.state.auth }
);
TypeScript
const schema = strapi.contentType('plugin::my-plugin.article');
const sanitizedOutput = await strapi.contentAPI.sanitize.output(
data,
schema,
{ auth: ctx.state.auth }
);
最佳实践
-
让导出键与
info.singularName完全一致。 这可保持命名可读且一致。在运行时,Strapi 从插件命名空间下contentTypes映射的键派生插件内容类型 UID。即便注册仍然成功,不匹配也可能产生令人困惑的 UID 和维护问题。 -
使用
collectionName以避免表名冲突。collectionName字段设置数据库表名。用插件名作为前缀(例如my_plugin_articles)以避免与应用内容类型或其他插件发生名称冲突。 -
将内容类型 schema 保存在各自的文件中。 在每个 schema 定义在以其
singularName命名的子文件夹内的专用schema.json文件中(例如content-types/article/schema.json)。这匹配 Plugin SDK 生成的结构,并使 index 文件保持可读。 -
仅在需要时启用
draftAndPublish。 草稿与发布会为内容类型添加发布工作流。仅当插件的用例需要时才启用它,因为它会增加查询和内容管理的复杂性。