From f8ef2f0f5c1489d2bbec4266f586e208683cef77 Mon Sep 17 00:00:00 2001 From: derrickmehaffy Date: Tue, 16 Nov 2021 08:46:34 -0700 Subject: [PATCH 01/15] update core example --- .../latest/development/backend-customization/controllers.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/developer-docs/latest/development/backend-customization/controllers.md b/docs/developer-docs/latest/development/backend-customization/controllers.md index 1ce146b18a..7684519e69 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -28,8 +28,10 @@ A new controller can be implemented: ```js // path: ./src/api/[api-name]/controllers/my-controller.js -module.exports = { - async exampleAction(ctx, next) { +const { createCoreController } = require('@strapi/strapi').factories; + +module.exports = createCoreController('api::address.address', { + async exampleAction(ctx) { try { ctx.body = 'ok'; } catch (err) { From 4dfade0162bd371dce4a2d46478bcc0a92dfe2d8 Mon Sep 17 00:00:00 2001 From: Pierre Wizla Date: Tue, 16 Nov 2021 17:12:06 +0100 Subject: [PATCH 02/15] Rewrite intro sentence --- .../latest/development/backend-customization/controllers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/developer-docs/latest/development/backend-customization/controllers.md b/docs/developer-docs/latest/development/backend-customization/controllers.md index 7684519e69..7189554b92 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -14,7 +14,7 @@ In most cases, the controllers will contain the bulk of a project's business log ## Implementation -Controllers can be [generated or added manually](#adding-a-new-controller), and the [core controllers examples](#extending-core-controllers) can help you get started creating custom ones. +Controllers can be [generated or added manually](#adding-a-new-controller). Strapi provides a `createCoreController` factory that automatically generates internal controllers and allows building custom ones or extend/replace the generated controllers. ### Adding a new controller From 6c3c37eaf5b4f30ae2a511ffa3995a0b822cadbc Mon Sep 17 00:00:00 2001 From: derrickmehaffy Date: Tue, 16 Nov 2021 09:15:23 -0700 Subject: [PATCH 03/15] collection type examples + other fixes --- .../backend-customization/controllers.md | 65 +++++++++++-------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/docs/developer-docs/latest/development/backend-customization/controllers.md b/docs/developer-docs/latest/development/backend-customization/controllers.md index 7684519e69..b98197b53f 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -26,17 +26,28 @@ A new controller can be implemented: - or in a folder like `./src/plugins/[plugin-name]/controllers/` for , though they can be created elsewhere as long as the plugin interface is properly exported in the `strapi-server.js` file (see [Server API for Plugins documentation](/developer-docs/latest/developer-resources/plugin-api-reference/server.md)) ```js -// path: ./src/api/[api-name]/controllers/my-controller.js +// path: ./src/api/restaurant/controllers/restaurant.js const { createCoreController } = require('@strapi/strapi').factories; -module.exports = createCoreController('api::address.address', { +module.exports = createCoreController('api::restaurant.restaurant', { async exampleAction(ctx) { try { ctx.body = 'ok'; } catch (err) { ctx.body = err; } + }, + async find(ctx) { + // some logic here + const { results, pagination } = await super.find(...args); + // some more logic + + return { results, pagination }; + }, + async find(ctx) { + // some entirely custom logic + return { okay: true } } }; ``` @@ -80,8 +91,9 @@ When a new [content-type](/developer-docs/latest/development/backend-customizati Default controllers are created for each content-type. These default controllers are used to return responses to API requests (e.g. when the `GET /api/articles/3` is accessed, the `findOne` method of the default controller for the "Article" content-type is called). Default controllers can be customized to implement your own logic. The following code examples should help you get started. -:::caution -v4 controllers are currently being refactored. The code examples below will be updated soon to reflect these changes. +:::tip Replacing core controllers +It's possible to replace the core controllers entirely by [creating a custom controller](#adding-a-new-controller) and naming it the same as the core controller. +(find, findOne, create, update, or delete) ::: @@ -93,11 +105,11 @@ v4 controllers are currently being refactored. The code examples below will be u ```js async find(ctx) { - const { query } = ctx; - - const { results, pagination } = await service.find(query); + // some logic here + const { results, pagination } = await super.find(ctx); + // some more logic - return transformResponse(sanitize(results), { pagination }); + return { results, pagination }; } ``` @@ -107,12 +119,11 @@ async find(ctx) { ```js async findOne(ctx) { - const { id } = ctx.params; - const { query } = ctx; - - const entity = await service.findOne(id, query); + // some logic here + const entity = await super.findOne(ctx); + // some more logic - return transformResponse(sanitize(entity)); + return entity; } ``` @@ -122,13 +133,11 @@ async findOne(ctx) { ```js async create(ctx) { - const { query } = ctx.request; + // some logic here + const entity = await super.create(ctx); + // some more logic - const { data, files } = parseBody(ctx); - - const entity = await service.create({ ...query, data, files }); - - return transformResponse(sanitize(entity)); + return entity; } ``` @@ -138,12 +147,11 @@ async create(ctx) { ```js async update(ctx) { - const { id } = ctx.params; - const { query } = ctx.request; - const { data, files } = parseBody(ctx); - const entity = await service.update(id, { ...query, data, files }); + // some logic here + const entity = await super.update(ctx); + // some more logic - return transformResponse(sanitize(entity)); + return entity; } ``` @@ -153,10 +161,11 @@ async update(ctx) { ```js async delete(ctx) { - const { id } = ctx.params; - const { query } = ctx; - const entity = await service.delete(id, query); - return transformResponse(sanitize(entity)); + // some logic here + const entity = await super.delete(ctx); + // some more logic + + return entity; } ``` From 2ff184667e7055ac6fe241d79b240a13de42ea5f Mon Sep 17 00:00:00 2001 From: derrickmehaffy Date: Tue, 16 Nov 2021 09:29:46 -0700 Subject: [PATCH 04/15] rewrite another example + singletypes --- .../backend-customization/controllers.md | 61 ++++++++++++------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/docs/developer-docs/latest/development/backend-customization/controllers.md b/docs/developer-docs/latest/development/backend-customization/controllers.md index e5a676b51b..b36ebe91bc 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -31,6 +31,7 @@ A new controller can be implemented: const { createCoreController } = require('@strapi/strapi').factories; module.exports = createCoreController('api::restaurant.restaurant', { + // Method 1 - Entirely Custom Controller async exampleAction(ctx) { try { ctx.body = 'ok'; @@ -38,6 +39,7 @@ module.exports = createCoreController('api::restaurant.restaurant', { ctx.body = err; } }, + // Method 2 - Wrapping Core controller (leaves core logic in place) async find(ctx) { // some logic here const { results, pagination } = await super.find(...args); @@ -45,6 +47,7 @@ module.exports = createCoreController('api::restaurant.restaurant', { return { results, pagination }; }, + // Method 3 - Replacing a core controller async find(ctx) { // some entirely custom logic return { okay: true } @@ -57,21 +60,30 @@ Every action receives a context object (`ctx`) as the first parameter. `ctx` con ::: details Example: GET /hello route calling a basic controller -A specific `GET /hello` [route](/developer-docs/latest/development/backend-customization/routes.md) is defined, which takes `hello.index` as a handler. Every time a `GET /hello` request is sent to the server, Strapi calls the `index` action in the `hello.js` controller, which returns `Hello World!`: +A specific `GET /hello` [route](/developer-docs/latest/development/backend-customization/routes.md) is defined, the name of the router `index` is used to call the controller handler `index`. Every time a `GET /hello` request is sent to the server, Strapi calls the `index` action in the `hello.js` controller, which returns `Hello World!`: ```js -// path: ./src/api/hello/routes/router.js - -module.exports = { - routes: [ - { - method: 'GET', - path: '/hello', - handler: 'hello.index', +// path: ./src/api/hello/routes/hello.js + +const { createCoreRouter } = require('@strapi/strapi').factories; + +module.exports = createCoreRouter('api::hello.hello', { + // prefix: '/someCustomPrefix', + // only: [], + // except: [], + index: { + method: 'GET', + path: '/hello', + config: { + auth: false + policies: [], + middlewares: []. } - ] + } } +``` +```js // path: ./src/api/hello/controllers/hello.js module.exports = { @@ -96,7 +108,6 @@ It's possible to replace the core controllers entirely by [creating a custom con (find, findOne, create, update, or delete) ::: - ::::: details Collection type examples :::: tabs card @@ -180,11 +191,12 @@ async delete(ctx) { ```js async find(ctx) { - const { query } = ctx; - const entity = await service.find(query); - return transformResponse(sanitize(entity)); -} + // some logic here + const entity = await super.find(ctx); + // some more logic + return entity; +} ``` ::: @@ -193,11 +205,11 @@ async find(ctx) { ```js async update(ctx) { - const { query } = ctx.request; - const { data, files } = parseBody(ctx); - const entity = await service.createOrUpdate({ ...query, data, files }); + // some logic here + const entity = await super.update(ctx); + // some more logic - return transformResponse(sanitize(entity)); + return entity; } ``` @@ -207,10 +219,11 @@ async update(ctx) { ```js async delete(ctx) { - const { query } = ctx; - const entity = await service.delete(query); + // some logic here + const entity = await super.delete(ctx); + // some more logic - return transformResponse(sanitize(entity)); + return entity; } ``` @@ -226,5 +239,7 @@ Controllers are declared and attached to a route. Controllers are automatically // access an API controller strapi.controller('api::api-name.controller-name'); // access a plugin controller -strapi.controller('plugin::plugin-name.service-name'); +strapi.controller('plugin::plugin-name.controller-name'); ``` + + From 1676dd137c801511a7fe271ae6af203d9a68a552 Mon Sep 17 00:00:00 2001 From: Pierre Wizla Date: Tue, 16 Nov 2021 17:29:49 +0100 Subject: [PATCH 05/15] Reword tip --- .../latest/development/backend-customization/controllers.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/developer-docs/latest/development/backend-customization/controllers.md b/docs/developer-docs/latest/development/backend-customization/controllers.md index b36ebe91bc..1cbacb76a3 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -103,9 +103,8 @@ When a new [content-type](/developer-docs/latest/development/backend-customizati Default controllers are created for each content-type. These default controllers are used to return responses to API requests (e.g. when the `GET /api/articles/3` is accessed, the `findOne` method of the default controller for the "Article" content-type is called). Default controllers can be customized to implement your own logic. The following code examples should help you get started. -:::tip Replacing core controllers -It's possible to replace the core controllers entirely by [creating a custom controller](#adding-a-new-controller) and naming it the same as the core controller. -(find, findOne, create, update, or delete) +:::tip +A core controller can be replaced entirely by [creating a custom controller](#adding-a-new-controller) and naming it the same as the core controller (e.g. `find`, `findOne`, `create`, `update`, or `delete`). ::: ::::: details Collection type examples From 9f28d586fc7b69fe8bb3ae02f4cc89fc217715bf Mon Sep 17 00:00:00 2001 From: derrickmehaffy Date: Tue, 16 Nov 2021 09:32:01 -0700 Subject: [PATCH 06/15] add cli command at bottom --- .../latest/development/backend-customization/controllers.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/developer-docs/latest/development/backend-customization/controllers.md b/docs/developer-docs/latest/development/backend-customization/controllers.md index b36ebe91bc..486aff6aec 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -243,3 +243,7 @@ strapi.controller('plugin::plugin-name.controller-name'); ``` + +::: tip +To list all the available controllers, run `yarn strapi controllers:list`. +::: From ee90fcc531fb9a3ec830147b20eba1a5e3be19c7 Mon Sep 17 00:00:00 2001 From: Pierre Wizla Date: Tue, 16 Nov 2021 17:59:08 +0100 Subject: [PATCH 07/15] Improve tech writing --- .../backend-customization/controllers.md | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/docs/developer-docs/latest/development/backend-customization/controllers.md b/docs/developer-docs/latest/development/backend-customization/controllers.md index fdfd6db039..35438a3d24 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -14,7 +14,7 @@ In most cases, the controllers will contain the bulk of a project's business log ## Implementation -Controllers can be [generated or added manually](#adding-a-new-controller). Strapi provides a `createCoreController` factory that automatically generates internal controllers and allows building custom ones or extend/replace the generated controllers. +Controllers can be [generated or added manually](#adding-a-new-controller). Strapi provides a `createCoreController` factory function that automatically generates core controllers and allows building custom ones or [extend/replace the generated controllers](#extending-core-controllers). ### Adding a new controller @@ -23,7 +23,7 @@ A new controller can be implemented: - with the [interactive CLI command `strapi generate`](/developer-docs/latest/developer-resources/cli/CLI.md#strapi-generate) - or manually by creating a JavaScript file: - in `./src/api/[api-name]/controllers/` for API controllers (this location matters as controllers are auto-loaded by Strapi from there) - - or in a folder like `./src/plugins/[plugin-name]/controllers/` for , though they can be created elsewhere as long as the plugin interface is properly exported in the `strapi-server.js` file (see [Server API for Plugins documentation](/developer-docs/latest/developer-resources/plugin-api-reference/server.md)) + - or in a folder like `./src/plugins/[plugin-name]/controllers/` for plugin controllers, though they can be created elsewhere as long as the plugin interface is properly exported in the `strapi-server.js` file (see [Server API for Plugins documentation](/developer-docs/latest/developer-resources/plugin-api-reference/server.md)) ```js // path: ./src/api/restaurant/controllers/restaurant.js @@ -31,7 +31,7 @@ A new controller can be implemented: const { createCoreController } = require('@strapi/strapi').factories; module.exports = createCoreController('api::restaurant.restaurant', { - // Method 1 - Entirely Custom Controller + // Method 1: Creating an entirely custom controller async exampleAction(ctx) { try { ctx.body = 'ok'; @@ -39,7 +39,8 @@ module.exports = createCoreController('api::restaurant.restaurant', { ctx.body = err; } }, - // Method 2 - Wrapping Core controller (leaves core logic in place) + + // Method 2: Wrapping a core controller (leaves core logic in place) async find(ctx) { // some logic here const { results, pagination } = await super.find(...args); @@ -47,7 +48,8 @@ module.exports = createCoreController('api::restaurant.restaurant', { return { results, pagination }; }, - // Method 3 - Replacing a core controller + + // Method 3: Replacing a core controller async find(ctx) { // some entirely custom logic return { okay: true } @@ -56,11 +58,11 @@ module.exports = createCoreController('api::restaurant.restaurant', { ``` Each controller action can be an `async` or `sync` function. -Every action receives a context object (`ctx`) as the first parameter. `ctx` contains the [request context](/developer-docs/latest/development/backend-customization/requests-responses.md#requests) and the [response context](/developer-docs/latest/development/backend-customization/requests-responses.md#responses). +Every action receives a context object (`ctx`) as a parameter. `ctx` contains the [request context](/developer-docs/latest/development/backend-customization/requests-responses.md#requests) and the [response context](/developer-docs/latest/development/backend-customization/requests-responses.md#responses). ::: details Example: GET /hello route calling a basic controller -A specific `GET /hello` [route](/developer-docs/latest/development/backend-customization/routes.md) is defined, the name of the router `index` is used to call the controller handler `index`. Every time a `GET /hello` request is sent to the server, Strapi calls the `index` action in the `hello.js` controller, which returns `Hello World!`: +A specific `GET /hello` [route](/developer-docs/latest/development/backend-customization/routes.md) is defined, the name of the router file (i.e. `index`) is used to call the controller handler (i.e. `index`). Every time a `GET /hello` request is sent to the server, Strapi calls the `index` action in the `hello.js` controller, which returns `Hello World!`: ```js // path: ./src/api/hello/routes/hello.js @@ -101,9 +103,9 @@ When a new [content-type](/developer-docs/latest/development/backend-customizati ### Extending core controllers -Default controllers are created for each content-type. These default controllers are used to return responses to API requests (e.g. when the `GET /api/articles/3` is accessed, the `findOne` method of the default controller for the "Article" content-type is called). Default controllers can be customized to implement your own logic. The following code examples should help you get started. +Default controllers are created for each content-type. These default controllers are used to return responses to API requests (e.g. when `GET /api/articles/3` is accessed, the `findOne` method of the default controller for the "Article" content-type is called). Default controllers can be customized to implement your own logic. The following code examples should help you get started. -:::tip +:::tip A core controller can be replaced entirely by [creating a custom controller](#adding-a-new-controller) and naming it the same as the core controller (e.g. `find`, `findOne`, `create`, `update`, or `delete`). ::: From 0650f176119eec722d3f4ef1eaa54da01283fa9d Mon Sep 17 00:00:00 2001 From: derrickmehaffy Date: Tue, 16 Nov 2021 13:01:00 -0700 Subject: [PATCH 08/15] Improve example --- .../backend-customization/controllers.md | 66 ++++++++++--------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/docs/developer-docs/latest/development/backend-customization/controllers.md b/docs/developer-docs/latest/development/backend-customization/controllers.md index fdfd6db039..b1e0adc2f5 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -30,7 +30,7 @@ A new controller can be implemented: const { createCoreController } = require('@strapi/strapi').factories; -module.exports = createCoreController('api::restaurant.restaurant', { +module.exports = createCoreController('api::restaurant.restaurant', ({ strapi }) => { // Method 1 - Entirely Custom Controller async exampleAction(ctx) { try { @@ -41,16 +41,25 @@ module.exports = createCoreController('api::restaurant.restaurant', { }, // Method 2 - Wrapping Core controller (leaves core logic in place) async find(ctx) { - // some logic here - const { results, pagination } = await super.find(...args); - // some more logic + // some custom logic here + ctx.query = { ...ctx.query, local: 'en' } + + const { data, meta } = await super.find(ctx); - return { results, pagination }; + // some more custom logic + meta.date = Date.now() + + return { data, meta }; }, // Method 3 - Replacing a core controller - async find(ctx) { - // some entirely custom logic - return { okay: true } + async findOne(ctx) { + const { id } = ctx.params; + const { query } = ctx; + + const entity = await strapi.service('api::restaurant.restaurant').findOne(id, query); + const sanitizedEntity = await this.sanitizeOutput(entity, ctx); + + return this.transformResponse(sanitizedEntity); } }; ``` @@ -65,21 +74,14 @@ A specific `GET /hello` [route](/developer-docs/latest/development/backend-custo ```js // path: ./src/api/hello/routes/hello.js -const { createCoreRouter } = require('@strapi/strapi').factories; - -module.exports = createCoreRouter('api::hello.hello', { - // prefix: '/someCustomPrefix', - // only: [], - // except: [], - index: { - method: 'GET', - path: '/hello', - config: { - auth: false - policies: [], - middlewares: []. +module.exports = { + routes: [ + { + method: 'GET', + path: '/hello', + handler: 'hello.index', } - } + ] } ``` @@ -116,10 +118,10 @@ A core controller can be replaced entirely by [creating a custom controller](#ad ```js async find(ctx) { // some logic here - const { results, pagination } = await super.find(ctx); + const { data, meta } = await super.find(ctx); // some more logic - return { results, pagination }; + return { data, meta }; } ``` @@ -130,10 +132,10 @@ async find(ctx) { ```js async findOne(ctx) { // some logic here - const entity = await super.findOne(ctx); + const response = await super.findOne(ctx); // some more logic - return entity; + return response; } ``` @@ -144,10 +146,10 @@ async findOne(ctx) { ```js async create(ctx) { // some logic here - const entity = await super.create(ctx); + const response = await super.create(ctx); // some more logic - return entity; + return response; } ``` @@ -158,10 +160,10 @@ async create(ctx) { ```js async update(ctx) { // some logic here - const entity = await super.update(ctx); + const response = await super.update(ctx); // some more logic - return entity; + return response; } ``` @@ -172,10 +174,10 @@ async update(ctx) { ```js async delete(ctx) { // some logic here - const entity = await super.delete(ctx); + const response = await super.delete(ctx); // some more logic - return entity; + return response; } ``` From 08b54eb836d06c97be46b0973a9ec749d562e800 Mon Sep 17 00:00:00 2001 From: derrickmehaffy Date: Tue, 16 Nov 2021 13:05:27 -0700 Subject: [PATCH 09/15] add additional comment to make it clear --- .../latest/development/backend-customization/controllers.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/developer-docs/latest/development/backend-customization/controllers.md b/docs/developer-docs/latest/development/backend-customization/controllers.md index ba4284cb6d..0b3ab495da 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -45,6 +45,7 @@ module.exports = createCoreController('api::restaurant.restaurant', ({ strapi }) // some custom logic here ctx.query = { ...ctx.query, local: 'en' } + // Calling the default core controller const { data, meta } = await super.find(ctx); // some more custom logic From 8407947c79675367a4be7016eb9c5d0aaabf4ae5 Mon Sep 17 00:00:00 2001 From: derrickmehaffy Date: Tue, 16 Nov 2021 14:05:02 -0700 Subject: [PATCH 10/15] Fix a few things in controllers and update service examples --- .../backend-customization/controllers.md | 14 +- .../backend-customization/services.md | 195 ++++++++++++++++-- 2 files changed, 183 insertions(+), 26 deletions(-) diff --git a/docs/developer-docs/latest/development/backend-customization/controllers.md b/docs/developer-docs/latest/development/backend-customization/controllers.md index 0b3ab495da..0c23f9b55c 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -196,10 +196,10 @@ async delete(ctx) { ```js async find(ctx) { // some logic here - const entity = await super.find(ctx); + const response = await super.find(ctx); // some more logic - return entity; + return response; } ``` @@ -210,10 +210,10 @@ async find(ctx) { ```js async update(ctx) { // some logic here - const entity = await super.update(ctx); + const response = await super.update(ctx); // some more logic - return entity; + return response; } ``` @@ -224,10 +224,10 @@ async update(ctx) { ```js async delete(ctx) { // some logic here - const entity = await super.delete(ctx); + const response = await super.delete(ctx); // some more logic - return entity; + return response; } ``` @@ -246,8 +246,6 @@ strapi.controller('api::api-name.controller-name'); strapi.controller('plugin::plugin-name.controller-name'); ``` - - ::: tip To list all the available controllers, run `yarn strapi controllers:list`. ::: diff --git a/docs/developer-docs/latest/development/backend-customization/services.md b/docs/developer-docs/latest/development/backend-customization/services.md index 402e8e5163..abb3b0eba1 100644 --- a/docs/developer-docs/latest/development/backend-customization/services.md +++ b/docs/developer-docs/latest/development/backend-customization/services.md @@ -1,5 +1,5 @@ --- -title: +title: Backend customization - Services - Strapi Developer Docs description: sidebarDepth: 3 --- @@ -12,6 +12,10 @@ Services are a set of reusable functions. They are particularly useful to respec ## Implementation +Services can be [generated or added manually](#adding-a-new-service). Strapi provides a `createCoreService` factory function that automatically generates core controllers and allows building custom ones or [extend/replace the generated controllers](#extending-core-services). + +### Adding a new service + A new service can be implemented: - with the [interactive CLI command `strapi generate`](/developer-docs/latest/developer-resources/cli/CLI.md#strapi-generate) @@ -22,15 +26,37 @@ 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: ```js -/** - * @param {{ strapi: import('@strapi/strapi').Strapi }} opts - */ -module.exports = ({ strapi }) => { - return { - archiveArticles(ids) { - // do some logic here - }, - }; +const { createCoreService } = require('@strapi/strapi').factories; + +module.exports = createCoreService('api::restaurant.restaurant', ({ strapi }) => { + // Method 1: Creating an entirely 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)); + } }; ``` @@ -45,6 +71,7 @@ The goal of a service is to store reusable functions. An `email` service could b ```js // path: ./src/api/email/services/email.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. @@ -56,8 +83,8 @@ const transporter = nodemailer.createTransport({ }, }); -module.exports = { - send: (from, to, subject, text) => { +module.exports = createCoreService('api::restaurant.restaurant', ({ strapi }) => { + send(from, to, subject, text) => { // Setup e-mail data. const options = { from, @@ -72,20 +99,21 @@ module.exports = { }; ``` -The service is now available through the `strapi.services` global variable. It can be used in another part of the codebase, like in the following controller: +The service is now available through the `strapi.service('api::email.email').send(...args)` global variable. It can be used in another part of the codebase, like in the following controller: ```js // path: ./src/api/user/controllers/user.js -module.exports = { +module.exports = createCoreController('api::restaurant.restaurant', ({ strapi }) => { // GET /hello - signup: async ctx => { + async signup(ctx) => { + const { userData } = ctx.body; + // Store the new user in database. - const user = await User.create(ctx.query); + const user = await strapi.service('api::users-permissions.user').add(userData); // Send an email to validate his subscriptions. - strapi.service('api::email.send')('welcome@mysite.com', user.email, 'Welcome', '...'); - + strapi.service('api::email.email').send('welcome@mysite.com', user.email, 'Welcome', '...'); // Send response to the server. ctx.send({ @@ -101,6 +129,137 @@ module.exports = { When a new [content-type](/developer-docs/latest/development/backend-customization/models.md#content-types) is created, Strapi builds a generic service with placeholder code, ready to be customized. ::: +### Extending core services + +Default services are created for each content-type. These default services are used to execute reusable logic when called throughout your Strapi project and most commonly are used by [controllers](/developer-docs/latest/development/backend-customization/controllers.md). Default 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](#adding-a-new-service) and naming it the same as the core service (e.g. `find`, `findOne`, `create`, `update`, or `delete`). +::: + +::::: details Collection type examples + +:::: tabs card + +::: tab find() + +```js +async find(params) { + // some logic here + const { results, pagination } = await super.find(params); + // some more logic + + return { results, pagination }; +} +``` + +::: + +::: tab findOne() + +```js +async findOne(entityId, params) { + // some logic here + const result = await super.findOne(entityId, params); + // some more logic + + return result; +} +``` + +::: + +::: tab create() + +```js +async create(params) { + // some logic here + const result = await super.create(params); + // some more logic + + return result; +} +``` + +::: + +::: tab update() + +```js +async update(entityId, params) { + // some logic here + const result = await super.update(entityId, params); + // some more logic + + return result; +} +``` + +::: + +::: tab delete() + +```js +async delete(entityId, params) { + // some logic here + const result = await super.delete(entityId, params); + // some more logic + + return result; +} +``` + +::: +:::: +::::: + +::::: details Single type examples +:::: tabs card + +::: tab find() + +```js +async find(params) { + // some logic here + const entity = await super.find(params); + // some more logic + + return entity; +} +``` + +::: + +::: tab update() + +```js +async createOrUpdate({ data, ...params }) { + // some logic here + const entity = await super.createOrUpdate({ data, ...params }); + // some more logic + + return entity; +} +``` + +::: + +::: tab delete() + +```js +async delete(params) { + // some logic here + const entity = await super.delete(params); + // some more logic + + return entity; +} +``` + +::: +:::: +::::: + ## Usage Once a service is created, it's accessible from [controllers](/developer-docs/latest/development/backend-customization/controllers.md) or from other services: From 20c7038161c62fb49329ccfad3c06da5293394d6 Mon Sep 17 00:00:00 2001 From: derrickmehaffy Date: Tue, 16 Nov 2021 14:13:07 -0700 Subject: [PATCH 11/15] forgot services path --- .../latest/development/backend-customization/services.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/developer-docs/latest/development/backend-customization/services.md b/docs/developer-docs/latest/development/backend-customization/services.md index abb3b0eba1..73c1b52e44 100644 --- a/docs/developer-docs/latest/development/backend-customization/services.md +++ b/docs/developer-docs/latest/development/backend-customization/services.md @@ -26,6 +26,8 @@ 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: ```js +// path: ./src/api/restaurant/services/restaurant.js + const { createCoreService } = require('@strapi/strapi').factories; module.exports = createCoreService('api::restaurant.restaurant', ({ strapi }) => { From 36cef4582bb81d0834cf668e4b6fdae504b682cf Mon Sep 17 00:00:00 2001 From: derrickmehaffy Date: Thu, 18 Nov 2021 08:42:49 -0700 Subject: [PATCH 12/15] Rewrite router docuementation --- .../backend-customization/routes.md | 216 +++++++++++++++--- 1 file changed, 183 insertions(+), 33 deletions(-) diff --git a/docs/developer-docs/latest/development/backend-customization/routes.md b/docs/developer-docs/latest/development/backend-customization/routes.md index 5a2901237c..90b274eb74 100644 --- a/docs/developer-docs/latest/development/backend-customization/routes.md +++ b/docs/developer-docs/latest/development/backend-customization/routes.md @@ -19,40 +19,84 @@ Once a route exists, reaching it executes some code handled by a controller (see Implementing a new route consists in defining it in a router file within the `.src/api/[apiName]/routes` folder (see [project structure](/developer-docs/latest/setup-deployment-guides/file-structure.md)). -A router file consists of an array of objects, each object being a route with the following parameters: +There are two different router file structures depending on if you are configuring the core routers or creating your own custom routers. Strapi provides a `createCoreRouter` factory function that automatically generates and allows for configuration of the core routers. -| Parameter | Description | Type | -| -------------------------- | -------------------------------------------------------------------------------- | -------- | -| `method` | Method associated to the route (i.e. `GET`, `POST`, `PUT`, `DELETE` or `PATCH`) | `String` | -| `path` | Path to reach, starting with a forward-leading slash (e.g. `/articles`)| `String` | -| `handler` | Function to execute when the route is reached.
Should follow this syntax: `.` | `String` | -| `config`

_Optional_ | Configuration to handle [policies](policies), [middlewares](middlewares) and [public availability](#public-routes) for the route

| `Object` | +### Core Routers + +For core routers (`find`, `findOne`, `create`, `update`, and `delete`), a default file is created that allows passing in some configuration options to each router and allowing you to disable certain core routers so you can create your own custom ones. The core router file structure has the following parameters: + +| Parameter | Description | Type | +| ----------| -------------------------------------------------------------------------------------------- | -------- | +| `prefix` | Allows passing in a custom prefix to add to all routers for this model (e.g. `/test`) | `String` | +| `only` | Array of core routes that will only be loaded, anything not in this array is ignored | `Array` | +| `except` | Array of core routes that should not be loaded, functionally the opposite of the only option | `Array` | +| `config` | Configuration to handle [policies](policies), [middlewares](middlewares) and [public availability](#public-routes) for the route | `Object` | + +Full Core Router configuration example: + +```js +const { createCoreRouter } = require('@strapi/strapi').factories; + +module.exports = createCoreRouter('api::restaurant.restaurant', { + prefix: '', + only: ['find', 'findOne'], + except: [], + config: { + find: { + auth: false, + policies: [], + middlewares: [], + }, + findOne: {}, + create: {}, + update: {}, + delete: {}, + }, +}); +``` Generic implementation example: -To handle any `GET` request on the `/articles` path by calling the `actionName` function from the `controllerName` [controller](/developer-docs/latest/development/backend-customization/controllers.md), use the following code: +To only allow a `GET` request on the `/restaurants` path from the core `find` [controller](/developer-docs/latest/development/backend-customization/controllers.md) without authentication, use the following code: +::: details Example of disabling authentication on a core route ```js -// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/blog/routes/articles.js') +// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/restaurant/routes/restaurant.js') -module.exports = { - routes: [ - { - method: 'GET', - path: '/articles', - handler: 'controllerName.actionName', - }, - ], -}; +const { createCoreRouter } = require('@strapi/strapi').factories; + +module.exports = createCoreRouter('api::restaurant.restaurant', { + only: ['find'], + config: { + find: { + auth: false + policies: [], + middlewares: [], + } + } +}); ``` -
+::: + +### Custom Routers + +For custom routers you will need to generate another router file that doesn't use the `createCoreRouter` factory this router file consists of an array of objects, each object being a route with the following parameters: + +| Parameter | Description | Type | +| -------------------------- | -------------------------------------------------------------------------------- | -------- | +| `method` | Method associated to the route (i.e. `GET`, `POST`, `PUT`, `DELETE` or `PATCH`) | `String` | +| `path` | Path to reach, starting with a forward-leading slash (e.g. `/articles`)| `String` | +| `handler` | Function to execute when the route is reached.
Should follow this syntax: `.` | `String` | +| `config`

_Optional_ | Configuration to handle [policies](policies), [middlewares](middlewares) and [public availability](#public-routes) for the route

| `Object` | + +Generic implementation example: The router used by Strapi allows the creation of dynamic routes, using parameters and regular expressions. These parameters will be exposed in the `ctx.params` object. For more details, please refer to the [PathToRegex](https://github.com/pillarjs/path-to-regexp) documentation. ::: details Example of routes using URL parameters and regular expressions ```js -// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/blog/routes/articles.js') +// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/restaurant/routes/custom-restaurant.js') module.exports = { routes: [ @@ -74,7 +118,7 @@ module.exports = { ## Configuration -The optional configuration for a route is defined in its `config` object, which can be used to handle [policies](#policies) and [middlewares](#middlewares) or to [make the route public](#public-routes). +Both the core routers and any custom routers you define in additional files have the same configuration options and is defined in its `config` object, which can be used to handle [policies](#policies) and [middlewares](#middlewares) or to [make the route public](#public-routes). ### Policies @@ -83,30 +127,71 @@ The optional configuration for a route is defined in its `config` object, which - by pointing to a policy registered in `./src/policies`, with or without passing a custom configuration - or by declaring the policy implementation directly, as a function that takes `policyContext` to extend [Koa's context](https://koajs.com/#context) (`ctx`) and the `strapi` instance as arguments (see [policies documentation](/developer-docs/latest/development/backend-customization/routes.md)) +:::: tabs + +::: tab Core Router - Policy + ```js -// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/blog/routes/articles.js') +// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/restaurant/routes/restaurant.js') + +const { createCoreRouter } = require('@strapi/strapi').factories; + +module.exports = createCoreRouter('api::restaurant.restaurant', { + config: { + find: { + policies: [ + // point to a registered policy + 'policy-name', + + // point to a registered policy with some custom configuration + { name: 'policy-name', config: {} }, + + // pass a policy implementation directly + (policyContext, config, { strapi }) => { + return true; + }, + ] + } + } +}); +``` + +::: + +::: tab Custom Router - Policy + +```js +// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/restaurant/routes/custom-restaurant.js') module.exports = { routes: [ { method: 'GET', - path: '/articles', + path: '/articles/customRoute', handler: 'controllerName.actionName', config: { policies: [ - 'policy-name', // point to a registered policy - { name: 'policy-name', config: {} }, // point to a registered policy with some custom configuration + // point to a registered policy + 'policy-name', + + // point to a registered policy with some custom configuration + { name: 'policy-name', config: {} }, + // pass a policy implementation directly (policyContext, config, { strapi }) => { return true; }, - ], + ] }, }, ], }; ``` +::: + +:::: + ### Middlewares [Middlewares](/developer-docs/latest/development/backend-customization/middlewares.md) can be added to a route configuration: @@ -114,19 +199,56 @@ module.exports = { - by pointing to a middleware registered in `./src/middlewares`, with or without passing a custom configuration - or by declaring the middleware implementation directly, as a function that takes [Koa's context](https://koajs.com/#context) (`ctx`) and the `strapi` instance as arguments: +:::: tabs + +::: tab Core Router - Middleware + +```js +// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/restaurant/routes/restaurant.js') + +const { createCoreRouter } = require('@strapi/strapi').factories; + +module.exports = createCoreRouter('api::restaurant.restaurant', { + config: { + find: { + middlwares: [ + // point to a registered middleware + 'middleware-name', + + // point to a registered middleware with some custom configuration + { name: 'middleware-name', config: {} }, + + // pass a middleware implementation directly + (ctx, next) => { + return next(); + }, + ] + } + } +}); +``` + +::: + +::: tab Custom Router - Middleware + ```js -// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/blog/routes/articles.js') +// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/restaurant/routes/custom-restaurant.js') module.exports = { routes: [ { method: 'GET', - path: '/articles', + path: '/articles/customRoute', handler: 'controllerName.actionName', config: { middlewares: [ - 'middleware-name', // point to a registered middleware - { name: 'middleware-name', config: {} }, // point to a registered middleware with some custom configuration + // point to a registered middleware + 'middleware-name', + + // point to a registered middleware with some custom configuration + { name: 'middleware-name', config: {} }, + // pass a middleware implementation directly (ctx, next) => { return next(); @@ -138,20 +260,46 @@ module.exports = { }; ``` +::: + +:::: + ### Public routes By default, routes are protected by Strapi's authentication system, which is based on [API tokens](/developer-docs/latest/setup-deployment-guides/configurations/required/admin-panel.md#api-tokens) or the use of a plugin such as the [Users & Permissions plugin](/user-docs/latest/plugins/strapi-plugins.md#users-permissions-plugin). In some scenarios, it can be useful to have a route publicly available and control the access outside of the normal Strapi authentication system. This can be achieved by setting the `auth` configuration parameter of a route to `false`: +:::: tabs + +::: tab Core Router - Public + +```js +// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/restaurant/routes/restaurant.js') + +const { createCoreRouter } = require('@strapi/strapi').factories; + +module.exports = createCoreRouter('api::restaurant.restaurant', { + config: { + find: { + auth: false + } + } +}); +``` + +::: + +::: tab Custom Router - Public + ```js -// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/blog/routes/articles.js') +// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/restaurant/routes/custom-restaurant.js') module.exports = { routes: [ { method: 'GET', - path: '/articles', + path: '/articles/customRoute', handler: 'controllerName.actionName', config: { auth: false, @@ -161,4 +309,6 @@ module.exports = { }; ``` -*** +::: + +:::: From f9a7decf44104fe4324a47d056271838ee3c362d Mon Sep 17 00:00:00 2001 From: Pierre Wizla Date: Thu, 18 Nov 2021 18:37:50 +0100 Subject: [PATCH 13/15] Tech writing improvements --- .../backend-customization/controllers.md | 2 +- .../backend-customization/routes.md | 78 +++++++++++-------- .../backend-customization/services.md | 6 +- 3 files changed, 50 insertions(+), 36 deletions(-) diff --git a/docs/developer-docs/latest/development/backend-customization/controllers.md b/docs/developer-docs/latest/development/backend-customization/controllers.md index 0c23f9b55c..cac1fd9320 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -14,7 +14,7 @@ In most cases, the controllers will contain the bulk of a project's business log ## Implementation -Controllers can be [generated or added manually](#adding-a-new-controller). Strapi provides a `createCoreController` factory function that automatically generates core controllers and allows building custom ones or [extend/replace the generated controllers](#extending-core-controllers). +Controllers can be [generated or added manually](#adding-a-new-controller). Strapi provides a `createCoreController` factory function that automatically generates core controllers and allows building custom ones or [extend or replace the generated controllers](#extending-core-controllers). ### Adding a new controller diff --git a/docs/developer-docs/latest/development/backend-customization/routes.md b/docs/developer-docs/latest/development/backend-customization/routes.md index 90b274eb74..f6e3841091 100644 --- a/docs/developer-docs/latest/development/backend-customization/routes.md +++ b/docs/developer-docs/latest/development/backend-customization/routes.md @@ -13,28 +13,40 @@ Requests sent to Strapi on any URL are handled by routes. By default, Strapi gen - with [policies](#policies), which are a way to block access to a route, - and with [middlewares](#middlewares), which are a way to control and change the request flow and the request itself. -Once a route exists, reaching it executes some code handled by a controller (see [controllers](/developer-docs/latest/development/backend-customization/controllers.md) documentation). +Once a route exists, reaching it executes some code handled by a controller (see [controllers documentation](/developer-docs/latest/development/backend-customization/controllers.md)). ## Implementation Implementing a new route consists in defining it in a router file within the `.src/api/[apiName]/routes` folder (see [project structure](/developer-docs/latest/setup-deployment-guides/file-structure.md)). -There are two different router file structures depending on if you are configuring the core routers or creating your own custom routers. Strapi provides a `createCoreRouter` factory function that automatically generates and allows for configuration of the core routers. +There are 2 different router file structures, depending on the use case: -### Core Routers +- configuring [core routers](#configuring-core-routers) +- or creating [custom routers](#creating-custom-routers). -For core routers (`find`, `findOne`, `create`, `update`, and `delete`), a default file is created that allows passing in some configuration options to each router and allowing you to disable certain core routers so you can create your own custom ones. The core router file structure has the following parameters: +### Configuring core routers + +Core routers (i.e. `find`, `findOne`, `create`, `update`, and `delete`) correspond to [default routes](/developer-docs/latest/developer-resources/database-apis-reference/rest-api.md#api-endpoints) automatically created by Strapi when a new [content-type](/developer-docs/latest/development/backend-customization/models.md#model-creation) is created. + +Strapi provides a `createCoreRouter` factory function that automatically generates the core routers and allows: + +- passing in configuration options to each router +- and disabling some core routers to [create custom ones](#creating-custom-routers). + +The core router file structure has the following parameters: | Parameter | Description | Type | | ----------| -------------------------------------------------------------------------------------------- | -------- | | `prefix` | Allows passing in a custom prefix to add to all routers for this model (e.g. `/test`) | `String` | -| `only` | Array of core routes that will only be loaded, anything not in this array is ignored | `Array` | -| `except` | Array of core routes that should not be loaded, functionally the opposite of the only option | `Array` | -| `config` | Configuration to handle [policies](policies), [middlewares](middlewares) and [public availability](#public-routes) for the route | `Object` | +| `only` | Core routes that will only be loaded

Anything not in this array is ignored. | `Array` | +| `except` | Core routes that should not be loaded

This is functionally the opposite of the `only` parameter. | `Array` | +| `config` | Configuration to handle [policies](#policies), [middlewares](#middlewares) and [public availability](#public-routes) for the route | `Object` | -Full Core Router configuration example: +
```js +// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/restaurant/routes/restaurant.js') + const { createCoreRouter } = require('@strapi/strapi').factories; module.exports = createCoreRouter('api::restaurant.restaurant', { @@ -55,13 +67,15 @@ module.exports = createCoreRouter('api::restaurant.restaurant', { }); ``` +
+ Generic implementation example: To only allow a `GET` request on the `/restaurants` path from the core `find` [controller](/developer-docs/latest/development/backend-customization/controllers.md) without authentication, use the following code: ::: details Example of disabling authentication on a core route ```js -// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/restaurant/routes/restaurant.js') +// path: ./src/api/restaurant/routes/restaurant.js const { createCoreRouter } = require('@strapi/strapi').factories; @@ -79,9 +93,9 @@ module.exports = createCoreRouter('api::restaurant.restaurant', { ::: -### Custom Routers +### Creating custom routers -For custom routers you will need to generate another router file that doesn't use the `createCoreRouter` factory this router file consists of an array of objects, each object being a route with the following parameters: +Creating custom routers consists in creating a file that exports an array of objects, each object being a route with the following parameters: | Parameter | Description | Type | | -------------------------- | -------------------------------------------------------------------------------- | -------- | @@ -90,13 +104,13 @@ For custom routers you will need to generate another router file that doesn't us | `handler` | Function to execute when the route is reached.
Should follow this syntax: `.` | `String` | | `config`

_Optional_ | Configuration to handle [policies](policies), [middlewares](middlewares) and [public availability](#public-routes) for the route

| `Object` | -Generic implementation example: +
-The router used by Strapi allows the creation of dynamic routes, using parameters and regular expressions. These parameters will be exposed in the `ctx.params` object. For more details, please refer to the [PathToRegex](https://github.com/pillarjs/path-to-regexp) documentation. +Dynamic routes can be created using parameters and regular expressions. These parameters will be exposed in the `ctx.params` object. For more details, please refer to the [PathToRegex](https://github.com/pillarjs/path-to-regexp) documentation. -::: details Example of routes using URL parameters and regular expressions +::: details Example of a custom router using URL parameters and regular expressions for routes ```js -// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/restaurant/routes/custom-restaurant.js') +// path: ./src/api/restaurant/routes/custom-restaurant.js module.exports = { routes: [ @@ -118,7 +132,7 @@ module.exports = { ## Configuration -Both the core routers and any custom routers you define in additional files have the same configuration options and is defined in its `config` object, which can be used to handle [policies](#policies) and [middlewares](#middlewares) or to [make the route public](#public-routes). +Both [core routers](#configuring-core-routers) and [custom routers](#creating-custom-routers) have the same configuration options. The routes configuration is defined in a `config` object that can be used to handle [policies](#policies) and [middlewares](#middlewares) or to [make the route public](#public-routes). ### Policies @@ -127,12 +141,12 @@ Both the core routers and any custom routers you define in additional files have - by pointing to a policy registered in `./src/policies`, with or without passing a custom configuration - or by declaring the policy implementation directly, as a function that takes `policyContext` to extend [Koa's context](https://koajs.com/#context) (`ctx`) and the `strapi` instance as arguments (see [policies documentation](/developer-docs/latest/development/backend-customization/routes.md)) -:::: tabs +:::: tabs card -::: tab Core Router - Policy +::: tab Core router policy ```js -// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/restaurant/routes/restaurant.js') +// path: ./src/api/restaurant/routes/restaurant.js const { createCoreRouter } = require('@strapi/strapi').factories; @@ -158,10 +172,10 @@ module.exports = createCoreRouter('api::restaurant.restaurant', { ::: -::: tab Custom Router - Policy +::: tab Custom router policy ```js -// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/restaurant/routes/custom-restaurant.js') +// path: ./src/api/restaurant/routes/custom-restaurant.js module.exports = { routes: [ @@ -199,12 +213,12 @@ module.exports = { - by pointing to a middleware registered in `./src/middlewares`, with or without passing a custom configuration - or by declaring the middleware implementation directly, as a function that takes [Koa's context](https://koajs.com/#context) (`ctx`) and the `strapi` instance as arguments: -:::: tabs +:::: tabs card -::: tab Core Router - Middleware +::: tab Core router middleware ```js -// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/restaurant/routes/restaurant.js') +// path: ./src/api/restaurant/routes/restaurant.js const { createCoreRouter } = require('@strapi/strapi').factories; @@ -230,10 +244,10 @@ module.exports = createCoreRouter('api::restaurant.restaurant', { ::: -::: tab Custom Router - Middleware +::: tab Custom router middleware ```js -// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/restaurant/routes/custom-restaurant.js') +// path: ./src/api/restaurant/routes/custom-restaurant.js module.exports = { routes: [ @@ -266,16 +280,16 @@ module.exports = { ### Public routes -By default, routes are protected by Strapi's authentication system, which is based on [API tokens](/developer-docs/latest/setup-deployment-guides/configurations/required/admin-panel.md#api-tokens) or the use of a plugin such as the [Users & Permissions plugin](/user-docs/latest/plugins/strapi-plugins.md#users-permissions-plugin). +By default, routes are protected by Strapi's authentication system, which is based on [API tokens](/developer-docs/latest/setup-deployment-guides/configurations/required/admin-panel.md#api-tokens) or on the use of the [Users & Permissions plugin](/user-docs/latest/plugins/strapi-plugins.md#users-permissions-plugin). In some scenarios, it can be useful to have a route publicly available and control the access outside of the normal Strapi authentication system. This can be achieved by setting the `auth` configuration parameter of a route to `false`: -:::: tabs +:::: tabs card -::: tab Core Router - Public +::: tab Core router with a public route ```js -// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/restaurant/routes/restaurant.js') +// path: ./src/api/restaurant/routes/restaurant.js const { createCoreRouter } = require('@strapi/strapi').factories; @@ -290,10 +304,10 @@ module.exports = createCoreRouter('api::restaurant.restaurant', { ::: -::: tab Custom Router - Public +::: tab Custom router with a public route ```js -// path: ./src/api/[apiName]/routes/[routerName].js (e.g './src/api/restaurant/routes/custom-restaurant.js') +// path: ./src/api/restaurant/routes/custom-restaurant.js module.exports = { routes: [ diff --git a/docs/developer-docs/latest/development/backend-customization/services.md b/docs/developer-docs/latest/development/backend-customization/services.md index 73c1b52e44..7f79a9b3f0 100644 --- a/docs/developer-docs/latest/development/backend-customization/services.md +++ b/docs/developer-docs/latest/development/backend-customization/services.md @@ -8,11 +8,11 @@ sidebarDepth: 3 # Services -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](/developer-docs/latest/development/backend-customization/controllers.md) logic. +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](/developer-docs/latest/development/backend-customization/controllers.md) logic. ## Implementation -Services can be [generated or added manually](#adding-a-new-service). Strapi provides a `createCoreService` factory function that automatically generates core controllers and allows building custom ones or [extend/replace the generated controllers](#extending-core-services). +Services can be [generated or added manually](#adding-a-new-service). Strapi provides a `createCoreService` factory function that automatically generates core controllers and allows building custom ones or [extend or replace the generated services](#extending-core-services). ### Adding a new service @@ -133,7 +133,7 @@ When a new [content-type](/developer-docs/latest/development/backend-customizati ### Extending core services -Default services are created for each content-type. These default services are used to execute reusable logic when called throughout your Strapi project and most commonly are used by [controllers](/developer-docs/latest/development/backend-customization/controllers.md). Default services can be customized to implement your own logic. The following code examples should help you get started. +Core services are created for each content-type and could be used by [controllers](/developer-docs/latest/development/backend-customization/controllers.md) 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](#adding-a-new-service) and naming it the same as the core service (e.g. `find`, `findOne`, `create`, `update`, or `delete`). From 3b2aa61ee1daf61e51542af6fc77880d63b3a19d Mon Sep 17 00:00:00 2001 From: Pierre Wizla Date: Tue, 23 Nov 2021 18:38:16 +0100 Subject: [PATCH 14/15] Use proper "action" wording --- .../development/backend-customization/controllers.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/developer-docs/latest/development/backend-customization/controllers.md b/docs/developer-docs/latest/development/backend-customization/controllers.md index cac1fd9320..2e35f7ba75 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -31,7 +31,7 @@ A new controller can be implemented: const { createCoreController } = require('@strapi/strapi').factories; module.exports = createCoreController('api::restaurant.restaurant', ({ strapi }) => { - // Method 1: Creating an entirely custom controller + // Method 1: Creating an entirely custom action async exampleAction(ctx) { try { ctx.body = 'ok'; @@ -40,12 +40,12 @@ module.exports = createCoreController('api::restaurant.restaurant', ({ strapi }) } }, - // Method 2: Wrapping a core controller (leaves core logic in place) + // Method 2: Wrapping a core action (leaves core logic in place) async find(ctx) { // some custom logic here ctx.query = { ...ctx.query, local: 'en' } - // Calling the default core controller + // Calling the default core action const { data, meta } = await super.find(ctx); // some more custom logic @@ -54,7 +54,7 @@ module.exports = createCoreController('api::restaurant.restaurant', ({ strapi }) return { data, meta }; }, - // Method 3: Replacing a core controller + // Method 3: Replacing a core action async findOne(ctx) { const { id } = ctx.params; const { query } = ctx; @@ -106,10 +106,10 @@ When a new [content-type](/developer-docs/latest/development/backend-customizati ### Extending core controllers -Default controllers are created for each content-type. These default controllers are used to return responses to API requests (e.g. when `GET /api/articles/3` is accessed, the `findOne` method of the default controller for the "Article" content-type is called). Default controllers can be customized to implement your own logic. The following code examples should help you get started. +Default controllers and actions are created for each content-type. These default controllers are used to return responses to API requests (e.g. when `GET /api/articles/3` is accessed, the `findOne` action of the default controller for the "Article" content-type is called). Default controllers can be customized to implement your own logic. The following code examples should help you get started. :::tip -A core controller can be replaced entirely by [creating a custom controller](#adding-a-new-controller) and naming it the same as the core controller (e.g. `find`, `findOne`, `create`, `update`, or `delete`). +An action from a core controller can be replaced entirely by [creating a custom controller](#adding-a-new-controller) and naming the action the same as the original action (e.g. `find`, `findOne`, `create`, `update`, or `delete`). ::: ::::: details Collection type examples From 6e311b22bf3de5025c1b92b047f34fad6fb77de5 Mon Sep 17 00:00:00 2001 From: Pierre Wizla Date: Wed, 24 Nov 2021 10:55:08 +0100 Subject: [PATCH 15/15] Update wording Co-authored-by: Alexandre BODIN --- .../latest/development/backend-customization/controllers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/developer-docs/latest/development/backend-customization/controllers.md b/docs/developer-docs/latest/development/backend-customization/controllers.md index 2e35f7ba75..ed296ec73b 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -109,7 +109,7 @@ When a new [content-type](/developer-docs/latest/development/backend-customizati Default controllers and actions are created for each content-type. These default controllers are used to return responses to API requests (e.g. when `GET /api/articles/3` is accessed, the `findOne` action of the default controller for the "Article" content-type is called). Default controllers can be customized to implement your own logic. The following code examples should help you get started. :::tip -An action from a core controller can be replaced entirely by [creating a custom controller](#adding-a-new-controller) and naming the action the same as the original action (e.g. `find`, `findOne`, `create`, `update`, or `delete`). +An action from a core controller can be replaced entirely by [creating a custom action](#adding-a-new-controller) and naming the action the same as the original action (e.g. `find`, `findOne`, `create`, `update`, or `delete`). ::: ::::: details Collection type examples