服务器 API:控制器和服务
🌐 Server API: Controllers & services
Page summary:
就像 Strapi 核心一样,插件也可以有控制器和服务。插件控制器处理 HTTP 层:它们接收
ctx、调用服务并返回响应。插件服务包含可重用的业务逻辑,并通过文档服务 API 与内容类型交互。保持控制器简 洁,将字段逻辑放在服务中。
控制器和服务是插件服务器中处理请求和业务逻辑的两个构建模块。它们在职责分离上协同工作:控制器负责 HTTP 层,服务负责字段层:
🌐 Controllers and services are the 2 building blocks that handle request processing and business logic in a plugin server. They work together in a clear separation of concerns: controllers own the HTTP layer, services own the domain layer:
| 目标 | 使用 || --- | --- || 接收 ctx,读取请求,设置响应 | 控制器 || 查询数据库或应用业务规则 | 服务 || 在多个控制器或生命周期钩子中重用逻辑 | 服务 || 作为请求的一部分调用外部 API | 服务 |
在深入了解本页的概念之前,请确保你已经:
🌐 Before diving deeper into the concepts on this page, please ensure you have:
- 创建了一个 Strapi 插件,
- 已阅读并理解了服务器 API的基础知识
控制器
🌐 Controllers
控制器是一个包含动作方法的对象,每个方法对应一个路由处理程序。控制器接收包含请求和响应的 Koa 上下文对象(ctx),调用相应的服务,并为响应设置 ctx.body 或 ctx.status。
🌐 A controller is an object of action methods, each corresponding to a route handler. Controllers receive a Koa context object (ctx) containing the request and response, call the appropriate service, and set ctx.body or ctx.status for the response.
声明
🌐 Declaration
控制器可以作为接收 { strapi } 的工厂函数导出,也可以作为普通对象导出。工厂函数模式是推荐的依赖注入方式,并且与大多数文档示例保持一致。
🌐 Controllers can be exported either as a factory function receiving { strapi } or as a plain object. The factory function pattern is the recommended approach for dependency injection and consistency with most documentation examples.
在运行时,Strapi 支持导出,并通过使用 { strapi } 调用它们来解析函数导出。
🌐 At runtime, Strapi supports both exports and resolves function exports by calling them with { strapi }.
controllers/index.js|ts 中使用的导出键必须与路由定义中使用的处理程序名称匹配。
🌐 The export key used in controllers/index.js|ts must match the handler name used in route definitions.
- JavaScript
- TypeScript
'use strict';
const article = require('./article');
module.exports = {
article,
};
'use strict';
module.exports = ({ strapi }) => ({
async find(ctx) {
const articles = await strapi
.plugin('my-plugin')
.service('article')
.findAll();
ctx.body = articles;
},
async findOne(ctx) {
const { documentId } = ctx.params;
const article = await strapi
.plugin('my-plugin')
.service('article')
.findOne(documentId);
if (!article) {
return ctx.notFound('Article not found');
}
ctx.body = article;
},
async create(ctx) {
const article = await strapi
.plugin('my-plugin')
.service('article')
.create(ctx.request.body);
ctx.status = 201;
ctx.body = article;
},
});
import article from './article';
export default {
article,
};
import type { Core } from '@strapi/strapi';
interface ArticleService {
findAll(): Promise<unknown[]>;
findOne(id: string): Promise<unknown>;
create(data: unknown): Promise<unknown>;
}
export default ({ strapi }: { strapi: Core.Strapi }) => ({
async find(ctx: any) {
// Limitation: in @strapi/types, plugin services are currently typed as unknown.
const articleService = strapi.plugin('my-plugin').service('article') as ArticleService;
ctx.body = await articleService.findAll();
},
async findOne(ctx: any) {
const { documentId } = ctx.params;
const article = await (strapi.plugin('my-plugin').service('article') as ArticleService).findOne(documentId);
if (!article) {
return ctx.notFound('Article not found');
}
ctx.body = article;
},
async create(ctx: any) {
const articleService = strapi.plugin('my-plugin').service('article') as ArticleService;
ctx.status = 201;
ctx.body = await articleService.create(ctx.request.body);
},
});