From f689703a82f5ce948c73b86293c93cdc990f7e03 Mon Sep 17 00:00:00 2001 From: Pierre Wizla Date: Wed, 20 Oct 2021 14:37:31 +0200 Subject: [PATCH 01/11] Update controllers documentation --- .../backend-customization/controllers.md | 362 +++--------------- 1 file changed, 48 insertions(+), 314 deletions(-) diff --git a/docs/developer-docs/latest/development/backend-customization/controllers.md b/docs/developer-docs/latest/development/backend-customization/controllers.md index 30da0080c4..0b06ba1527 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -1,355 +1,89 @@ --- -title: +title: Backend customization - Controllers - Strapi Developer Docs description: +sidebarDepth: 3 --- # Controllers -Controllers are JavaScript files which contain a set of methods called **actions** reached by the client according to the requested route. It means that every time a client requests the route, the action performs the business logic code and sends back the response. They represent the _C_ in the _MVC_ pattern. In most cases, the controllers will contain the bulk of a project's business logic. +Controllers are JavaScript files that contain a set of methods, called actions, reached by the client according to the requested [route](/developer-docs/latest/development/backend-customization/routes.md). Whenever a client requests the route, the action performs the business logic code and sends back the [response](/developer-docs/latest/development/backend-customization#responses). Controllers represent the C in the model-view-controller (MVC) pattern. Just like [all the other parts of the Strapi backend](/developer-docs/latest/development/backend-customization.md), controllers can be customized. -```js -module.exports = { - // GET /hello - async index(ctx) { - return 'Hello World!'; - }, -}; -``` - -In this example, any time a web browser is pointed to the `/hello` URL on your app, the page will display the text: `Hello World!`. - -The controllers are defined in each `./api/**/controllers/` folder. Every JavaScript file put in these folders will be loaded as a controller. They are also available through the `strapi.controllers` and `strapi.api.**.controllers` global variables. - -## Core controllers - -When you create a new `Content Type` you will see a new empty controller has been created. This is because Strapi builds a generic controller for your models by default and allows you to override and extend it in the generated files. - -### Extending a Model Controller - -Here are the core methods (and their current implementation). -You can simply copy and paste this code in your own controller file to customize the methods. - -:::caution -In the following example we will assume your controller, service and model are named `restaurant`. -::: - -#### Utils - -First require the utility functions - -```js -const { parseMultipartData, sanitizeEntity } = require('strapi-utils'); -``` +In most cases, the controllers will contain the bulk of a project's business logic. But as a controller's logic becomes more and more complicated, it's a good practice to use [services](/developer-docs/latest/development/backend-customization/services.md) to organize the code into re-usable parts. + -- `parseMultipartData`: This function parses Strapi's formData format. -- `sanitizeEntity`: This function removes all private fields from the model and its relations. +## Implementation -#### Collection Type +A new controller can be implemented: -:::: tabs card - -::: tab find - -##### `find` +- with the [interactive CLI command `strapi generate`]() + +- or manually by creating a JavaScript file in the appropriate folder (see [project structure](/developer-docs/latest/setup-deployment-guides/file-structure.md)): + - `./src/api/[api-name]/controllers/` for API controllers + - or `./src/plugins/[plugin-name]/controllers/` for [plugin controllers](/developer-docs/latest/developer-resources/plugin-api-reference/server.md#controllers). ```js -const { sanitizeEntity } = require('strapi-utils'); +// path: ./src/api/[api-name]/controllers/my-controller.js module.exports = { - /** - * Retrieve records. - * - * @return {Array} - */ - - async find(ctx) { - let entities; - if (ctx.query._q) { - entities = await strapi.services.restaurant.search(ctx.query); - } else { - entities = await strapi.services.restaurant.find(ctx.query); + exampleAction: async (ctx, next) => { + try { + ctx.body = 'ok'; + } catch (err) { + ctx.body = err; } - - return entities.map(entity => sanitizeEntity(entity, { model: strapi.contentType('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). + -::: tab findOne +::: details Example: GET /hello route calling a basic controller -##### `findOne` +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!`: + ```js -const { sanitizeEntity } = require('strapi-utils'); - -module.exports = { - /** - * Retrieve a record. - * - * @return {Object} - */ - - async findOne(ctx) { - const { id } = ctx.params; +// path: ./src/api/hello/routes/router.js - const entity = await strapi.services.restaurant.findOne({ id }); - return sanitizeEntity(entity, { model: strapi.contentType('api::restaurant.restaurant') }); - }, -}; -``` - -::: - -::: tab count - -##### `count` - -```js module.exports = { - /** - * Count records. - * - * @return {Number} - */ - - count(ctx) { - if (ctx.query._q) { - return strapi.services.restaurant.countSearch(ctx.query); - } - return strapi.services.restaurant.count(ctx.query); - }, -}; -``` - -::: - -::: tab create - -##### `create` - -```js -const { parseMultipartData, sanitizeEntity } = require('strapi-utils'); - -module.exports = { - /** - * Create a record. - * - * @return {Object} - */ - - async create(ctx) { - let entity; - if (ctx.is('multipart')) { - const { data, files } = parseMultipartData(ctx); - entity = await strapi.services.restaurant.create(data, { files }); - } else { - entity = await strapi.services.restaurant.create(ctx.request.body); - } - return sanitizeEntity(entity, { model: strapi.contentType('api::restaurant.restaurant') }); - }, -}; -``` - -::: - -::: tab update - -##### `update` - -```js -const { parseMultipartData, sanitizeEntity } = require('strapi-utils'); - -module.exports = { - /** - * Update a record. - * - * @return {Object} - */ - - async update(ctx) { - const { id } = ctx.params; - - let entity; - if (ctx.is('multipart')) { - const { data, files } = parseMultipartData(ctx); - entity = await strapi.services.restaurant.update({ id }, data, { - files, - }); - } else { - entity = await strapi.services.restaurant.update({ id }, ctx.request.body); + routes: [ + { + method: 'GET', + path: '/hello', + handler: 'hello.index', } + ] +} - return sanitizeEntity(entity, { model: strapi.contentType('api::restaurant.restaurant') }); - }, -}; -``` - -::: - -::: tab delete - -##### `delete` - -```js -const { sanitizeEntity } = require('strapi-utils'); - -module.exports = { - /** - * Delete a record. - * - * @return {Object} - */ - - async delete(ctx) { - const { id } = ctx.params; - - const entity = await strapi.services.restaurant.delete({ id }); - return sanitizeEntity(entity, { model: strapi.contentType('api::restaurant.restaurant') }); - }, -}; -``` - -::: - -:::: - -#### Single Type - -:::: tabs card - -::: tab find - -##### `find` - -```js -const { sanitizeEntity } = require('strapi-utils'); - -module.exports = { - /** - * Retrieve the record. - * - * @return {Object} - */ - - async find(ctx) { - const entity = await strapi.services.homepage.find(); - return sanitizeEntity(entity, { model: strapi.models.homepage }); - }, -}; -``` - -::: - -::: tab update - -##### `update` - -```js -const { parseMultipartData, sanitizeEntity } = require('strapi-utils'); +// path: ./src/api/hello/controllers/hello.js module.exports = { - /** - * Update the record. - * - * @return {Object} - */ - - async update(ctx) { - let entity; - if (ctx.is('multipart')) { - const { data, files } = parseMultipartData(ctx); - entity = await strapi.services.restaurant.createOrUpdate(data, { - files, - }); - } else { - entity = await strapi.services.restaurant.createOrUpdate(ctx.request.body); - } - - return sanitizeEntity(entity, { model: strapi.contentType('api::restaurant.restaurant') }); + index: async (ctx, next) => { // called by GET /hello + ctx.body = 'Hello World!'; // we could also send a JSON }, }; ``` ::: -::: tab delete - -##### `delete` - -```js -const { sanitizeEntity } = require('strapi-utils'); - -module.exports = { - /** - * Delete the record. - * - * @return {Object} - */ - - async delete(ctx) { - const entity = await strapi.services.restaurant.delete(); - return sanitizeEntity(entity, { model: strapi.contentType('api::restaurant.restaurant') }); - }, -}; -``` +When a new [content-type](/developer-docs/latest/development/backend-customization/models.md#content-types) is created, Strapi builds a generic controller for it and allows overriding and extending it in the generated files. +::: tip +Use the code for the default controller actions of [collection types](https://github.com/strapi/strapi/blob/releases/v4/packages/core/strapi/lib/core-api/controller/collection-type.js) and [single types](https://github.com/strapi/strapi/blob/releases/v4/packages/core/strapi/lib/core-api/controller/single-type.js) in Strapi's Github repository to create custom controllers or extend the existing ones. + ::: -:::: - -## Custom controllers - -You can also create custom controllers to build your own business logic and API endpoints. - -There are two ways to create a controller: - -- Using the CLI `strapi generate:controller restaurant`.
Read the [CLI documentation](/developer-docs/latest/developer-resources/cli/CLI.md#strapi-generate-controller) for more information. -- Manually create a JavaScript file in `./api/**/controllers`. - -### Adding Endpoints - -Each controller’s action can be an `async` or `sync` function. -Every action receives a `context` (`ctx`) object as first parameter containing 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). - -### Example +## Usage -In this example, we are defining a specific route in `./api/hello/config/routes.json` that takes `hello.index` as handler. For more information on routing, please see the [Routing documentation](/developer-docs/latest/development/backend-customization/routing.md) +Controllers are called different ways depending on their scope: -It means that every time a request `GET /hello` is sent to the server, Strapi will call the `index` action in the `hello.js` controller. -Our `index` action will return `Hello World!`. You can also return a JSON object. - -**Path —** `./api/hello/config/routes.json`. - -```json -{ - "routes": [ - { - "method": "GET", - "path": "/hello", - "handler": "hello.index", - "config": { - "policies": [] - } - } - ] -} -``` - -**Path —** `./api/hello/controllers/hello.js`. - -```js -module.exports = { - // GET /hello - async index(ctx) { - ctx.send('Hello World!'); - }, -}; -``` - -::: tip -A route handler can only access the controllers defined in the `./api/**/controllers` folders. -::: +- for API controllers, use: + - `strapi.api('api-name').controller('controller-name')` + - or `strapi.controller('api::api-name.controller-name')` +- for plugin controllers, use: + - `strapi.plugin('plugin-name').controller('controller-name')` + - or `strapi.controller('plugin::plugin-name.controller-name')` From 4d9c62d5e0dd79de3cd78f454ea7cf30087f9b22 Mon Sep 17 00:00:00 2001 From: Pierre Wizla Date: Wed, 20 Oct 2021 14:50:38 +0200 Subject: [PATCH 02/11] Remove sidebarDepth in yaml as default level (2) is enough --- .../latest/development/backend-customization/controllers.md | 1 - 1 file changed, 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 0b06ba1527..849404da71 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -1,7 +1,6 @@ --- title: Backend customization - Controllers - Strapi Developer Docs description: -sidebarDepth: 3 --- From 3d2cb0dab5fc6a4518908507476ee3d7e321cdd2 Mon Sep 17 00:00:00 2001 From: Pierre Wizla Date: Wed, 20 Oct 2021 14:51:37 +0200 Subject: [PATCH 03/11] Delete unused backend-customization.md file --- docs/developer-docs/latest/development/backend-customization.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/developer-docs/latest/development/backend-customization.md diff --git a/docs/developer-docs/latest/development/backend-customization.md b/docs/developer-docs/latest/development/backend-customization.md deleted file mode 100644 index e69de29bb2..0000000000 From 0436625bb47675f7e3863a375df2c5edfff95b62 Mon Sep 17 00:00:00 2001 From: Pierre Wizla Date: Wed, 20 Oct 2021 14:56:00 +0200 Subject: [PATCH 04/11] Add link to plugin controllers in project structure docs --- .../latest/setup-deployment-guides/file-structure.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/developer-docs/latest/setup-deployment-guides/file-structure.md b/docs/developer-docs/latest/setup-deployment-guides/file-structure.md index 37c9026e76..ff47e09699 100644 --- a/docs/developer-docs/latest/setup-deployment-guides/file-structure.md +++ b/docs/developer-docs/latest/setup-deployment-guides/file-structure.md @@ -88,6 +88,7 @@ The default structure of a Strapi project created without the starter CLI looks │ │ │ └──── src │ │ │ └ index.js │ │ ├──── server +│ │ ├──── controllers │ │ ├ package.json │ │ ├ strapi-admin.js │ │ └ strapi-server.js From ec6c1fa91c250c3bcfac1652be70cb6fb37b92f6 Mon Sep 17 00:00:00 2001 From: Pierre Wizla Date: Wed, 20 Oct 2021 16:44:47 +0200 Subject: [PATCH 05/11] Re-introduce core controllers examples Note: Code examples are not usable as-is, will be reworked with devs. --- .../backend-customization/controllers.md | 139 +++++++++++++++++- 1 file changed, 135 insertions(+), 4 deletions(-) diff --git a/docs/developer-docs/latest/development/backend-customization/controllers.md b/docs/developer-docs/latest/development/backend-customization/controllers.md index 849404da71..6a5752edee 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -14,6 +14,10 @@ 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. + +### Adding a new controller + A new controller can be implemented: - with the [interactive CLI command `strapi generate`]() @@ -69,12 +73,139 @@ module.exports = { ::: -When a new [content-type](/developer-docs/latest/development/backend-customization/models.md#content-types) is created, Strapi builds a generic controller for it and allows overriding and extending it in the generated files. +::: note +When a new [content-type](/developer-docs/latest/development/backend-customization/models.md#content-types) is created, Strapi builds a generic controller with placeholder code, ready to be customized. +::: + +### Extending core controllers + +Strapi's core API provide actions built into controller files for collection types and single types. The following code examples should help you get started creating custom actions for controllers: + + + +::::: details Collection type examples + +:::: tabs card + +::: tab find() + +```js +async find(ctx) { + const { query } = ctx; + + const { results, pagination } = await service.find(query); + + return transformResponse(sanitize(results), { pagination }); +} +``` + +::: + +::: tab findOne() + +```js +async findOne(ctx) { + const { id } = ctx.params; + const { query } = ctx; + + const entity = await service.findOne(id, query); + + return transformResponse(sanitize(entity)); +} +``` + +::: + +::: tab create() + +```js +async create(ctx) { + const { query } = ctx.request; + + const { data, files } = parseBody(ctx); + + const entity = await service.create({ ...query, data, files }); + + return transformResponse(sanitize(entity)); +} +``` + +::: + +::: tab update() + +```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 }); + + return transformResponse(sanitize(entity)); +} +``` + +::: + +::: tab delete() + +```js +async delete(ctx) { + const { id } = ctx.params; + const { query } = ctx; + const entity = await service.delete(id, query); + return transformResponse(sanitize(entity)); +} +``` + +::: +:::: +::::: + +::::: details Single type examples +:::: tabs card + +::: tab find() + +```js +async find(ctx) { + const { query } = ctx; + const entity = await service.find(query); + return transformResponse(sanitize(entity)); +} + +``` + +::: + +::: tab update() + +```js +async update(ctx) { + const { query } = ctx.request; + const { data, files } = parseBody(ctx); + const entity = await service.createOrUpdate({ ...query, data, files }); + + return transformResponse(sanitize(entity)); +} +``` + +::: + +::: tab delete() + +```js +async delete(ctx) { + const { query } = ctx; + const entity = await service.delete(query); + + return transformResponse(sanitize(entity)); +} +``` -::: tip -Use the code for the default controller actions of [collection types](https://github.com/strapi/strapi/blob/releases/v4/packages/core/strapi/lib/core-api/controller/collection-type.js) and [single types](https://github.com/strapi/strapi/blob/releases/v4/packages/core/strapi/lib/core-api/controller/single-type.js) in Strapi's Github repository to create custom controllers or extend the existing ones. - ::: +:::: +::::: ## Usage From 9572c1ae3026715f8d1b54caf1e3844ec44bbfc0 Mon Sep 17 00:00:00 2001 From: Pierre Wizla Date: Wed, 20 Oct 2021 16:56:39 +0200 Subject: [PATCH 06/11] Go a level deeper in sidebar --- .../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 6a5752edee..e24c4521ab 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -1,6 +1,7 @@ --- title: Backend customization - Controllers - Strapi Developer Docs description: +sidebarDepth: 3 --- From e4d2f71188e7d9505bcb047e637ba598cae761f7 Mon Sep 17 00:00:00 2001 From: Pierre Wizla Date: Wed, 20 Oct 2021 17:15:01 +0200 Subject: [PATCH 07/11] Simplify controller usage section --- .../backend-customization/controllers.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/developer-docs/latest/development/backend-customization/controllers.md b/docs/developer-docs/latest/development/backend-customization/controllers.md index e24c4521ab..e2695630c3 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -210,11 +210,11 @@ async delete(ctx) { ## Usage -Controllers are called different ways depending on their scope: - -- for API controllers, use: - - `strapi.api('api-name').controller('controller-name')` - - or `strapi.controller('api::api-name.controller-name')` -- for plugin controllers, use: - - `strapi.plugin('plugin-name').controller('controller-name')` - - or `strapi.controller('plugin::plugin-name.controller-name')` +Once a controller is created, it's accessible from other parts of the customization code: + +```js +// access an API controller +strapi.controller('api::api-name.controller-name'); +// access a plugin controller +strapi.controller('plugin::plugin-name.service-name'); +``` From 884deb551ee026a98d9486fffee258fc5e876927 Mon Sep 17 00:00:00 2001 From: Pierre Wizla Date: Thu, 28 Oct 2021 23:19:17 +0200 Subject: [PATCH 08/11] Add link to strapi generate CLI docs --- .../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 e2695630c3..35edf185be 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -21,7 +21,7 @@ Controllers can be [generated or added manually](#adding-a-new-controller), and A new controller can be implemented: -- with the [interactive CLI command `strapi generate`]() +- 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 the appropriate folder (see [project structure](/developer-docs/latest/setup-deployment-guides/file-structure.md)): - `./src/api/[api-name]/controllers/` for API controllers From 7dcf62e06bc551d05ee7f11871ea05c2118c5fe5 Mon Sep 17 00:00:00 2001 From: Pierre Wizla Date: Mon, 8 Nov 2021 16:08:20 +0100 Subject: [PATCH 09/11] Improve core controllers intro based on Pierre N's feedback --- .../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 35edf185be..d58097d92b 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -80,7 +80,7 @@ When a new [content-type](/developer-docs/latest/development/backend-customizati ### Extending core controllers -Strapi's core API provide actions built into controller files for collection types and single types. The following code examples should help you get started creating custom actions for controllers: +Default controllers are created for each of the content-types created. They 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 Content-Type article). Default controllers can be customized to implement your own logic. The following code examples should help you get started. From 57d94c08044d1652ccb5657121c1806b0776830f Mon Sep 17 00:00:00 2001 From: Pierre Wizla Date: Mon, 8 Nov 2021 16:55:19 +0100 Subject: [PATCH 10/11] Improve some controllers explanations --- .../development/backend-customization/controllers.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/developer-docs/latest/development/backend-customization/controllers.md b/docs/developer-docs/latest/development/backend-customization/controllers.md index d58097d92b..4bebe0fcd6 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -23,9 +23,9 @@ 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 the appropriate folder (see [project structure](/developer-docs/latest/setup-deployment-guides/file-structure.md)): - - `./src/api/[api-name]/controllers/` for API controllers - - or `./src/plugins/[plugin-name]/controllers/` for [plugin controllers](/developer-docs/latest/developer-resources/plugin-api-reference/server.md#controllers). +- 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)) ```js // path: ./src/api/[api-name]/controllers/my-controller.js @@ -80,7 +80,7 @@ When a new [content-type](/developer-docs/latest/development/backend-customizati ### Extending core controllers -Default controllers are created for each of the content-types created. They 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 Content-Type article). 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 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. @@ -210,7 +210,7 @@ async delete(ctx) { ## Usage -Once a controller is created, it's accessible from other parts of the customization code: +Controllers are declared and attached to a route. Controllers are automatically called when the route is called, so controllers usually do not need to be called explicitly. However, [services](/developer-docs/latest/development/backend-customization/services.md) can call controllers, and in this case the following syntax should be used: ```js // access an API controller From f7a32c5b9281bf82a715394b67a499e41efcbcfe Mon Sep 17 00:00:00 2001 From: Pierre Wizla Date: Mon, 8 Nov 2021 16:55:36 +0100 Subject: [PATCH 11/11] Add a temporary caution while controllers are under rework --- .../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 4bebe0fcd6..324fe9236e 100644 --- a/docs/developer-docs/latest/development/backend-customization/controllers.md +++ b/docs/developer-docs/latest/development/backend-customization/controllers.md @@ -82,6 +82,10 @@ 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. +::: + ::::: details Collection type examples