Skip to main content

服务

¥Services

服务是一组可重用的功能。它们对于尊重 "不要重复自己" (DRY) 编程概念和简化 controllers 逻辑特别有用。

¥Services are a set of reusable functions. They are particularly useful to respect the "don’t repeat yourself" (DRY) programming concept and to simplify controllers logic.

Simplified Strapi backend diagram with services highlighted
The diagram represents a simplified version of how a request travels through the Strapi back end, with services highlighted. The backend customization introduction page includes a complete, interactive diagram.

执行

¥Implementation

服务可以 手动生成或添加。Strapi 提供了 createCoreService 工厂功能,可自动生成核心服务并允许构建自定义服务或 扩展或替换生成的服务

¥Services can be generated or added manually. Strapi provides a createCoreService factory function that automatically generates core services and allows building custom ones or extend or replace the generated services.

添加新服务

¥Adding a new service

可以实现一个新的服务:

¥A new service can be implemented:

要手动创建服务,请导出返回服务实现的工厂函数(即具有方法的对象)。该工厂函数接收 strapi 实例:

¥To manually create a service, export a factory function that returns the service implementation (i.e. an object with methods). This factory function receives the strapi instance:

./src/api/restaurant/services/restaurant.js

const { createCoreService } = require('@strapi/strapi').factories;

module.exports = createCoreService('api::restaurant.restaurant', ({ strapi }) => ({
// Method 1: Creating an entirely new custom service
async exampleService(...args) {
let response = { okay: true }

if (response.okay === false) {
return { response, error: true }
}

return response
},

// Method 2: Wrapping a core service (leaves core logic in place)
async find(...args) {
// Calling the default core controller
const { results, pagination } = await super.find(...args);

// some custom logic
results.forEach(result => {
result.counter = 1;
});

return { results, pagination };
},

// Method 3: Replacing a core service
async findOne(documentId, params = {}) {
return strapi.documents('api::restaurant.restaurant').findOne(documentId, this.getFetchParams(params));
}
}));
🤓 文档服务 API

要开始创建你自己的服务,请参阅 文档服务 API 文档中的 Strapi 内置函数。

¥To get started creating your own services, see Strapi's built-in functions in the Document Service API documentation.

Example of a custom email service (using Nodemailer)

服务的目标是存储可重用的功能。sendNewsletter 服务可用于从我们的代码库中具有特定目的的不同功能发送电子邮件:

¥The goal of a service is to store reusable functions. A sendNewsletter service could be useful to send emails from different functions in our codebase that have a specific purpose:

./src/api/restaurant/services/restaurant.js


const { createCoreService } = require('@strapi/strapi').factories;


const nodemailer = require('nodemailer'); // Requires nodemailer to be installed (npm install nodemailer)



// Create reusable transporter object using SMTP transport.


const transporter = nodemailer.createTransport({


service: 'Gmail',
auth: {
user: 'user@gmail.com',
pass: 'password',
},
});

module.exports = createCoreService('api::restaurant.restaurant', ({ strapi }) => ({
sendNewsletter(from, to, subject, text) {
// Setup e-mail data.
const options = {
from,
to,
subject,
text,
};

// Return a promise of the function that sends the email.
return transporter.sendMail(options);
},
}));

现在可以通过 strapi.service('api::restaurant.restaurant').sendNewsletter(...args) 全局变量使用该服务。它可以在代码库的另一部分中使用,例如在以下控制器中:

¥The service is now available through the strapi.service('api::restaurant.restaurant').sendNewsletter(...args) global variable. It can be used in another part of the codebase, like in the following controller:

./src/api/restaurant/controllers/restaurant.js

module.exports = createCoreController('api::restaurant.restaurant', ({ strapi }) => ({
// GET /hello
async signup(ctx) {
const { userData } = ctx.body;

// Store the new user in database.
const user = await strapi.service('plugin::users-permissions.user').add(userData);

// Send an email to validate his subscriptions.
strapi.service('api::restaurant.restaurant').sendNewsletter('welcome@mysite.com', user.email, 'Welcome', '...');

// Send response to the server.
ctx.send({
ok: true,
});
},
}));
✏️ 注意

当创建新的 content-type 时,Strapi 会使用占位符代码构建通用服务,准备进行自定义。

¥When a new content-type is created, Strapi builds a generic service with placeholder code, ready to be customized.

拓展核心服务

¥Extending core services

核心服务是为每种内容类型创建的,controllers 可以使用核心服务通过 Strapi 项目执行可重用逻辑。可以定制核心服务来实现你自己的逻辑。以下代码示例应该可以帮助你入门。

¥Core services are created for each content-type and could be used by controllers to execute reusable logic through a Strapi project. Core services can be customized to implement your own logic. The following code examples should help you get started.

💡 提示

核心服务可以完全替换为 创建定制服务,并将其命名为与核心服务相同的名称(例如 findfindOnecreateupdatedelete)。

¥A core service can be replaced entirely by creating a custom service and naming it the same as the core service (e.g. find, findOne, create, update, or delete).

Collection type examples
async find(params) {
// some logic here
const { results, pagination } = await super.find(params);
// some more logic

return { results, pagination };
}
Single type examples
async find(params) {
// some logic here
const document = await super.find(params);
// some more logic

return document;
}

用法

¥Usage

创建服务后,可以从 controllers 或其他服务访问它:

¥Once a service is created, it's accessible from controllers or from other services:

// access an API service
strapi.service('api::apiName.serviceName').FunctionName();
// access a plugin service
strapi.service('plugin::pluginName.serviceName').FunctionName();

在上面的语法示例中,serviceName 是 API 服务的服务文件的名称,或者用于将服务文件导出到 services/index.js 的插件服务的名称。

¥In the syntax examples above, serviceName is the name of the service file for API services or the name used to export the service file to services/index.js for plugin services.

💡 提示

要列出所有可用服务,请运行 yarn strapi services:list

¥To list all the available services, run yarn strapi services:list.