2019-05-06 16:17:16 +02:00
# Services
2019-10-09 12:32:58 +02:00
## Concept
Services are a set of reusable functions. They are particularly useful to respect the DRY (don’ t repeat yourself) programming concept and to simplify [controllers ](./controllers.md ) logic.
2019-05-06 16:17:16 +02:00
2019-05-16 15:00:55 +02:00
## Core services
2019-05-06 16:17:16 +02:00
2020-03-20 17:45:47 +04:00
When you create a new `Content Type` or a new model, you will see a new empty service has been created. It is because Strapi builds a generic service for your models by default and allows you to override and extend it in the generated files.
2019-05-16 15:00:55 +02:00
### Extending a Model Service
Here are the core methods (and their current implementation).
2019-05-24 14:42:53 +02:00
You can simply copy and paste this code to your own service file to customize the methods.
2019-05-16 15:00:55 +02:00
2020-02-08 17:56:01 +01:00
You can read about `strapi.query` calls [here ](./queries.md ).
2019-05-16 21:37:45 +02:00
2019-11-07 12:05:39 +01:00
::: tip
2020-02-08 17:56:01 +01:00
In the following example your controller, service and model are named `restaurant` .
2019-05-16 15:00:55 +02:00
:::
2019-11-07 12:05:39 +01:00
:::: tabs
2019-10-09 12:32:58 +02:00
2019-11-07 12:05:39 +01:00
::: tab find
2019-10-09 12:32:58 +02:00
2019-05-16 15:00:55 +02:00
#### `find`
```js
module.exports = {
/**
* Promise to fetch all records
*
* @return {Promise}
*/
find(params, populate) {
2019-09-24 17:27:02 +02:00
return strapi.query('restaurant').find(params, populate);
2019-05-16 15:00:55 +02:00
},
};
```
2020-04-01 11:48:38 +02:00
- `params` (object): this represent filters for your find request.< br >
The object follow the URL query format, [refer to this documentation. ](content-api/parameters.html ).
```json
{
"name": "Tokyo Sushi"
}
// or
{
"_limit": 20,
"name_contains": "sushi"
}
```
- `populate` (array): you have to mention data you want populate `["author", "author.name", "comment", "comment.content"]`
2019-10-09 12:32:58 +02:00
:::
2019-11-07 12:05:39 +01:00
::: tab findOne
2019-10-09 12:32:58 +02:00
2019-05-16 15:00:55 +02:00
#### `findOne`
```js
module.exports = {
/**
* Promise to fetch record
*
* @return {Promise}
*/
findOne(params, populate) {
2019-09-24 17:27:02 +02:00
return strapi.query('restaurant').findOne(params, populate);
2019-05-16 15:00:55 +02:00
},
};
```
2020-04-01 11:48:38 +02:00
- `params` (object): this represent filters for your find request.< br >
The object follow the URL query format, [refer to this documentation. ](content-api/parameters.html ).
```json
{
"name": "Tokyo Sushi"
}
// or
{
"name_contains": "sushi"
}
```
- `populate` (array): you have to mention data you want populate `["author", "author.name", "comment", "comment.content"]`
2019-10-09 12:32:58 +02:00
:::
2019-11-07 12:05:39 +01:00
::: tab count
2019-10-09 12:32:58 +02:00
2019-05-16 15:00:55 +02:00
#### `count`
```js
module.exports = {
/**
* Promise to count record
*
* @return {Promise}
*/
count(params) {
2019-09-24 17:27:02 +02:00
return strapi.query('restaurant').count(params);
2019-05-16 15:00:55 +02:00
},
};
```
2020-04-01 11:48:38 +02:00
- `params` (object): this represent filters for your find request.< br >
The object follow the URL query format, [refer to this documentation. ](content-api/parameters.html ).
```json
{
"name": "Tokyo Sushi"
}
// or
{
"name_contains": "sushi"
}
```
2019-10-09 12:32:58 +02:00
:::
2019-11-07 12:05:39 +01:00
::: tab create
2019-10-09 12:32:58 +02:00
2019-05-16 15:00:55 +02:00
#### `create`
```js
module.exports = {
/**
* Promise to add record
*
* @return {Promise}
*/
2019-08-12 16:58:18 +02:00
async create(data, { files } = {}) {
2020-04-13 14:58:37 +02:00
const entry = await strapi.query('restaurant').create(data);
2019-08-12 16:58:18 +02:00
if (files) {
// automatically uploads the files based on the entry and the model
2020-02-25 20:06:12 +01:00
await strapi.entityService.uploadFiles(entry, files, {
2020-04-13 14:58:37 +02:00
model: 'restaurant',
// if you are using a plugin's model you will have to add the `plugin` key (plugin: 'users-permissions')
2020-02-25 20:06:12 +01:00
});
2019-08-12 16:58:18 +02:00
return this.findOne({ id: entry.id });
}
return entry;
2019-05-16 15:00:55 +02:00
},
};
```
2019-10-09 12:32:58 +02:00
:::
2019-11-07 12:05:39 +01:00
::: tab update
2019-10-09 12:32:58 +02:00
2019-05-16 15:00:55 +02:00
#### `update`
```js
module.exports = {
/**
* Promise to edit record
*
* @return {Promise}
*/
2019-08-12 16:58:18 +02:00
async update(params, data, { files } = {}) {
2020-04-13 14:58:37 +02:00
const entry = await strapi.query('restaurant').update(params, data);
2019-08-12 16:58:18 +02:00
if (files) {
// automatically uploads the files based on the entry and the model
2020-02-25 20:06:12 +01:00
await strapi.entityService.uploadFiles(entry, files, {
2020-04-13 15:01:21 +02:00
model: 'restaurant',
2020-04-13 14:58:37 +02:00
// if you are using a plugin's model you will have to add the `plugin` key (plugin: 'users-permissions')
2020-02-25 20:06:12 +01:00
});
2019-08-12 16:58:18 +02:00
return this.findOne({ id: entry.id });
}
return entry;
2019-05-16 15:00:55 +02:00
},
};
```
2020-04-01 11:48:38 +02:00
- `params` (object): if should looks like this `{id: 1}`
2019-10-09 12:32:58 +02:00
:::
2019-11-07 12:05:39 +01:00
::: tab delete
2019-10-09 12:32:58 +02:00
2019-05-16 15:00:55 +02:00
#### `delete`
```js
module.exports = {
/**
* Promise to delete a record
*
* @return {Promise}
*/
delete(params) {
2019-09-24 17:27:02 +02:00
return strapi.query('restaurant').delete(params);
2019-05-16 15:00:55 +02:00
},
};
```
2020-04-01 11:48:38 +02:00
- `params` (object): if should looks like this `{id: 1}`
2019-10-09 12:32:58 +02:00
:::
2019-11-07 12:05:39 +01:00
::: tab search
2019-10-09 12:32:58 +02:00
2019-05-16 15:00:55 +02:00
#### `search`
2020-04-18 10:17:37 +02:00
```js
2019-05-16 15:00:55 +02:00
module.exports = {
/**
* Promise to search records
*
* @return {Promise}
*/
search(params) {
2019-09-24 17:27:02 +02:00
return strapi.query('restaurant').search(params);
2019-05-16 15:00:55 +02:00
},
};
```
2020-04-01 11:48:38 +02:00
- `params` (object): this represent filters for your find request.< br >
The object follow the URL query format, [refer to this documentation. ](content-api/parameters.html ).
```json
{
"name": "Tokyo Sushi"
}
// or
{
"name_contains": "sushi"
}
```
2019-10-09 12:32:58 +02:00
:::
2019-11-07 12:05:39 +01:00
::: tab countSearch
2019-10-09 12:32:58 +02:00
2019-05-16 15:00:55 +02:00
#### `countSearch`
```js
module.exports = {
/**
* Promise to count searched records
*
* @return {Promise}
*/
countSearch(params) {
2019-09-24 17:27:02 +02:00
return strapi.query('restaurant').countSearch(params);
2019-05-16 15:00:55 +02:00
},
};
```
2020-04-01 11:48:38 +02:00
- `params` (object): this represent filters for your find request.< br >
The object follow the URL query format, [refer to this documentation. ](content-api/parameters.html ).
```json
{
"name": "Tokyo Sushi"
}
// or
{
"name_contains": "sushi"
}
```
2019-10-09 12:32:58 +02:00
:::
::::
2019-05-16 15:00:55 +02:00
## Custom services
You can also create custom services to build your own business logic.
### How to create a custom service
There are two ways to create a service.
2020-04-01 11:48:38 +02:00
- Using the CLI `strapi generate:service restaurant` .< br > Read the [CLI documentation ](../cli/CLI.md ) for more information.
2019-05-16 15:00:55 +02:00
- Manually create a JavaScript file named in `./api/**/services/` .
2019-05-06 16:17:16 +02:00
#### Example
2019-05-24 14:42:53 +02:00
The goal of a service is to store reusable functions. An `email` service could be useful to send emails from different functions in our codebase:
2019-05-06 16:17:16 +02:00
**Path —** `./api/email/services/Email.js` .
2019-05-16 15:00:55 +02:00
2019-05-06 16:17:16 +02:00
```js
const nodemailer = require('nodemailer');
// Create reusable transporter object using SMTP transport.
const transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'user@gmail .com',
2019-05-16 15:00:55 +02:00
pass: 'password',
},
2019-05-06 16:17:16 +02:00
});
module.exports = {
2019-05-16 15:00:55 +02:00
send: (from, to, subject, text) => {
2019-05-06 16:17:16 +02:00
// Setup e-mail data.
const options = {
from,
to,
subject,
2019-05-16 15:00:55 +02:00
text,
2019-05-06 16:17:16 +02:00
};
// Return a promise of the function that sends the email.
return transporter.sendMail(options);
2019-05-16 15:00:55 +02:00
},
2019-05-06 16:17:16 +02:00
};
```
2019-11-07 12:05:39 +01:00
::: tip
2019-05-06 16:17:16 +02:00
please make sure you installed `nodemailer` (`npm install nodemailer` ) for this example.
:::
The service is now available through the `strapi.services` global variable. We can use it in another part of our codebase. For example a controller like below:
**Path —** `./api/user/controllers/User.js` .
2019-05-16 15:00:55 +02:00
2019-05-06 16:17:16 +02:00
```js
module.exports = {
// GET /hello
2019-05-16 15:00:55 +02:00
signup: async ctx => {
2019-05-06 16:17:16 +02:00
// Store the new user in database.
2020-04-02 18:10:22 +02:00
const user = await User.create(ctx.query);
2019-05-06 16:17:16 +02:00
// Send an email to validate his subscriptions.
2020-03-04 09:32:13 +01:00
strapi.services.email.send('welcome@mysite .com', user.email, 'Welcome', '...');
2019-05-06 16:17:16 +02:00
// Send response to the server.
ctx.send({
2019-05-16 15:00:55 +02:00
ok: true,
2019-05-06 16:17:16 +02:00
});
2019-05-16 15:00:55 +02:00
},
2019-05-06 16:17:16 +02:00
};
```