Skip to main content

Services

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.

Implementation​

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:

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(entityId, params = {}) {
return strapi.entityService.findOne('api::restaurant.restaurant', entityId, this.getFetchParams(params));
}
}));
Entity Service API

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

Example of a custom email service (using Nodemailer)

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);
},
}));

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,
});
},
}));
note

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

Extending core services​

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.

tip

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 entity = await super.find(params);
// some more logic

return entity;
}

Usage​

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

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

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