服务器 API:内容类型
🌐 Server API: Content-types
Page summary:服务器 API 从服务器入口文件导出一个
contentTypes对象以声明插件内容类型。推荐的命名约定是对导出键和值info.singularName使用相同的值,以便在查询或清理数据时运行时 UID 保持可预测。
插件可以通过从 服务器入口文件 导出一个 contentTypes 对象来声明自己的内容类型。Strapi 在启动时会在插件命名空间下注册这些内容类型,并通过文档服务 API 和内容类型注册表提供访问。
🌐 A plugin can declare its own content-types by exporting a contentTypes object from the server entry file. Strapi registers these content-types under the plugin namespace at startup and makes them available through the Document Service API and the content-type registry.
在深入了解本页的概念之前,请确保你已经:
🌐 Before diving deeper into the concepts on this page, please ensure you have:
- 创建了一个 Strapi 插件,
- 已阅读并理解了服务器 API的基础知识
声明
🌐 Declaration
contentTypes 导出是一个对象,其中每个键在插件命名空间下注册一种内容类型。为了避免混淆,该键应与模式中的 info.singularName 字段匹配。该值是一个对象,具有一个指向模式定义的 schema 属性。
🌐 The contentTypes export is an object where each key registers a content-type under the plugin namespace. To avoid confusion, the key should match the info.singularName field in the schema. The value is an object with a schema property pointing to the schema definition.
- JavaScript
- TypeScript
'use strict';
const article = require('./article');
module.exports = {
article: { schema: article }, // recommended: keep key aligned with info.singularName
};
{
"kind": "collectionType",
"collectionName": "my_plugin_articles",
"info": {
"singularName": "article",
"pluralName": "articles",
"displayName": "Article"
},
"options": {
"draftAndPublish": false
},
"attributes": {
"title": {
"type": "string",
"required": true
},
"body": {
"type": "richtext"
}
}
}
import article from './article';
export default {
article: { schema: article }, // recommended: keep key aligned with info.singularName
};
{
"kind": "collectionType",
"collectionName": "my_plugin_articles",
"info": {
"singularName": "article",
"pluralName": "articles",
"displayName": "Article"
},
"options": {
"draftAndPublish": false
},
"attributes": {
"title": {
"type": "string",
"required": true
},
"body": {
"type": "richtext"
}
}
}
UID 和命名规范
🌐 UIDs and naming conventions
当注册插件内容类型时,Strapi 会从插件命名空间和在 contentTypes 导出中使用的键构建其运行时 UID:
🌐 When a plugin content-type is registered, Strapi builds its runtime UID from the plugin namespace and the key used in the contentTypes export:
plugin::<plugin-name>.<content-types-key>
推荐的做法是设置 content-types-key === info.singularName。遵循这个做法可以使模式命名和运行时 UID 保持一致,并且更易于阅读。
🌐 The recommended convention is to set content-types-key === info.singularName. Following this convention keeps the schema naming and runtime UID aligned and easier to read.
当密钥匹配 singularName(推荐)时,生成的 UID 采用以下格式:
🌐 When the key matches singularName (recommended), the resulting UID follows this format:
plugin::<plugin-name>.<singular-name>
例如,一个名为 my-plugin 的插件,其内容类型的 singularName 是 article,导出键是 article,其 UID 是 plugin::my-plugin.article。
🌐 For example, a plugin named my-plugin with a content-type whose singularName is article and export key article has the UID plugin::my-plugin.article.
如果 contentTypes 键和 info.singularName 出现分歧,getter 和查询将使用从注册键构建的 UID(而不是从 singularName 构建)。这可能会在你的插件代码中引入命名不一致。
🌐 If the contentTypes key and info.singularName diverge, getters and queries use the UID built from the registered key (not from singularName). This can introduce naming inconsistencies across your plugin code.
此 UID 在所有 API 中都保持一致使用:
🌐 This UID is used consistently across all APIs:
| 用例 | 示例 |
|---|---|
| 通过文档服务查询 | strapi.documents('plugin::my-plugin.article').findMany() |
| 通过 getter 访问模式 | strapi.contentType('plugin::my-plugin.article') |
| 在路由处理程序中引用 | handler: 'article.find'(简短形式,通过插件注册表解析) |
| 传递给清理 API | strapi.contentAPI.sanitize.output(data, schema, { auth }) |
控制器、服务、策略和中间件对全局 getter 使用相同的 plugin::<plugin-name>.<resource-name> UID 格式,但在插件级 API 中(例如路由 handler 和 policies)通过它们的短注册表键(例如 'article')进行引用。详情请参见 Getters & usage。
运行时访问
🌐 Access at runtime
使用文档服务 API 进行查询
🌐 Querying with the Document Service API
使用文档服务 API 从控制器、服务或生命周期钩子中查询插件内容类型:
🌐 Use the Document Service API to query plugin content-types from controllers, services, or lifecycle hooks:
- JavaScript
- TypeScript
module.exports = ({ strapi }) => ({
async findAll(params = {}) {
return strapi.documents('plugin::my-plugin.article').findMany(params);
},
async create(data) {
return strapi.documents('plugin::my-plugin.article').create({ data });
},
});
import type { Core } from '@strapi/strapi';
export default ({ strapi }: { strapi: Core.Strapi }) => ({
async findAll(params: Record<string, unknown> = {}) {
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。
🌐 For the full list of available methods and parameters, see the Document Service API.
访问架构
🌐 Accessing the schema
使用内容类型获取器来获取模式对象,例如将其传递给清理 API:
🌐 Use the content-type getter to retrieve the schema object, for example to pass it to the sanitization API:
- JavaScript
- TypeScript
const schema = strapi.contentType('plugin::my-plugin.article');
const sanitizedOutput = await strapi.contentAPI.sanitize.output(
data,
schema,
{ auth: ctx.state.auth }
);
const schema = strapi.contentType('plugin::my-plugin.article');
const sanitizedOutput = await strapi.contentAPI.sanitize.output(
data,
schema,
{ auth: ctx.state.auth }
);
最佳实践
🌐 Best practices
- 将导出键精确匹配为
info.singularName。 这样可以保持命名的可读性和一致性。在运行时,Strapi 会从插件命名空间下contentTypes映射的键中派生插件内容类型 UID。即使注册仍然成功,不匹配也可能会产生混乱的 UID 和维护问题。 - 使用
collectionName避免表名冲突。collectionName字段用于设置数据库表的名称。将其前缀加上插件名称(例如my_plugin_articles),以避免与应用内容类型或其他插件发生冲突。 - 将内容类型的模式保存在自己的文件中。 在名为
singularName的子文件夹中,为每个模式定义一个专用的schema.json文件(例如,content-types/article/schema.json)。这与插件 SDK 生成的结构相匹配,并保持索引文件的可读性。 - 仅在需要时启用
draftAndPublish。 草稿和发布为内容类型添加了一个发布工作流程。仅在插件的使用场景需要时启用它,因为它会增加查询和内容管理的复杂性。