@strapi/strapi 4.0.0-beta.11 → 4.0.0-beta.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/lib/Strapi.js +3 -3
  2. package/lib/commands/new.js +3 -1
  3. package/lib/core/domain/module/index.js +3 -1
  4. package/lib/core/domain/module/validation.js +1 -4
  5. package/lib/core/loaders/plugins/get-enabled-plugins.js +25 -9
  6. package/lib/core/loaders/plugins/index.js +16 -6
  7. package/lib/core/registries/apis.js +2 -16
  8. package/lib/core/registries/controllers.d.ts +7 -0
  9. package/lib/core/registries/controllers.js +74 -3
  10. package/lib/core/registries/services.js +15 -6
  11. package/lib/core-api/controller/collection-type.js +37 -23
  12. package/lib/core-api/controller/index.d.ts +25 -0
  13. package/lib/core-api/controller/index.js +15 -10
  14. package/lib/core-api/controller/single-type.js +23 -16
  15. package/lib/core-api/routes/index.js +71 -0
  16. package/lib/core-api/service/collection-type.js +5 -7
  17. package/lib/core-api/service/index.d.ts +21 -0
  18. package/lib/core-api/service/index.js +9 -12
  19. package/lib/core-api/service/single-type.js +6 -4
  20. package/lib/factories.d.ts +48 -0
  21. package/lib/factories.js +84 -0
  22. package/lib/index.d.ts +1 -0
  23. package/lib/index.js +5 -1
  24. package/lib/middlewares/errors.js +1 -1
  25. package/lib/middlewares/index.d.ts +1 -0
  26. package/lib/middlewares/security.js +7 -2
  27. package/lib/services/entity-service/index.d.ts +1 -1
  28. package/lib/services/entity-service/index.js +8 -7
  29. package/lib/services/entity-validator/index.js +10 -1
  30. package/lib/services/errors.js +8 -3
  31. package/lib/services/server/compose-endpoint.js +21 -7
  32. package/lib/services/server/policy.js +5 -9
  33. package/lib/services/server/register-routes.js +1 -3
  34. package/package.json +13 -13
  35. package/lib/core-api/index.js +0 -39
package/lib/Strapi.js CHANGED
@@ -366,7 +366,7 @@ class Strapi {
366
366
  this.telemetry.bootstrap();
367
367
 
368
368
  let oldContentTypes;
369
- if (await this.db.connection.schema.hasTable(coreStoreModel.collectionName)) {
369
+ if (await this.db.getSchemaConnection().hasTable(coreStoreModel.collectionName)) {
370
370
  oldContentTypes = await this.store.get({
371
371
  type: 'strapi',
372
372
  name: 'content_types',
@@ -463,13 +463,13 @@ class Strapi {
463
463
  await this.container.get('modules')[lifecycleName]();
464
464
 
465
465
  // user
466
- const userLifecycleFunction = this.app[lifecycleName];
466
+ const userLifecycleFunction = this.app && this.app[lifecycleName];
467
467
  if (isFunction(userLifecycleFunction)) {
468
468
  await userLifecycleFunction({ strapi: this });
469
469
  }
470
470
 
471
471
  // admin
472
- const adminLifecycleFunction = this.admin[lifecycleName];
472
+ const adminLifecycleFunction = this.admin && this.admin[lifecycleName];
473
473
  if (isFunction(adminLifecycleFunction)) {
474
474
  await adminLifecycleFunction({ strapi: this });
475
475
  }
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ const { generateNewApp } = require('@strapi/generate-new');
4
+
3
5
  /**
4
6
  * `$ strapi new`
5
7
  *
@@ -7,5 +9,5 @@
7
9
  */
8
10
 
9
11
  module.exports = function(...args) {
10
- return require('@strapi/generate-new')(...args);
12
+ return generateNewApp(...args);
11
13
  };
@@ -61,7 +61,9 @@ const createModule = (namespace, rawModule, strapi) => {
61
61
  strapi.container.get('controllers').add(namespace, rawModule.controllers);
62
62
  strapi.container.get('config').set(uidToPath(namespace), rawModule.config);
63
63
  },
64
- routes: rawModule.routes,
64
+ get routes() {
65
+ return rawModule.routes;
66
+ },
65
67
  config(path, defaultValue) {
66
68
  return strapi.container.get('config').get(`${uidToPath(namespace)}.${path}`, defaultValue);
67
69
  },
@@ -1,6 +1,5 @@
1
1
  'use strict';
2
2
 
3
- const _ = require('lodash');
4
3
  const { yup } = require('@strapi/utils');
5
4
 
6
5
  const strapiServerSchema = yup
@@ -14,9 +13,7 @@ const strapiServerSchema = yup
14
13
  if (Array.isArray(value)) {
15
14
  return yup.array();
16
15
  } else {
17
- const shape = _.mapValues(value, () => yup.object({ routes: yup.array().required() }));
18
-
19
- return yup.object(shape);
16
+ return yup.object();
20
17
  }
21
18
  }),
22
19
  controllers: yup.object(),
@@ -51,10 +51,10 @@ const getEnabledPlugins = async strapi => {
51
51
  const packageInfo = require(packagePath);
52
52
 
53
53
  validatePluginName(packageInfo.strapi.name);
54
- internalPlugins[packageInfo.strapi.name] = toDetailedDeclaration({
55
- enabled: true,
56
- resolve: packagePath,
57
- });
54
+ internalPlugins[packageInfo.strapi.name] = {
55
+ ...toDetailedDeclaration({ enabled: true, resolve: packagePath }),
56
+ info: packageInfo.strapi,
57
+ };
58
58
  }
59
59
 
60
60
  const installedPlugins = {};
@@ -64,10 +64,10 @@ const getEnabledPlugins = async strapi => {
64
64
 
65
65
  if (isStrapiPlugin(packageInfo)) {
66
66
  validatePluginName(packageInfo.strapi.name);
67
- installedPlugins[packageInfo.strapi.name] = toDetailedDeclaration({
68
- enabled: true,
69
- resolve: packagePath,
70
- });
67
+ installedPlugins[packageInfo.strapi.name] = {
68
+ ...toDetailedDeclaration({ enabled: true, resolve: packagePath }),
69
+ info: packageInfo.strapi,
70
+ };
71
71
  }
72
72
  }
73
73
 
@@ -79,7 +79,23 @@ const getEnabledPlugins = async strapi => {
79
79
 
80
80
  _.forEach(userPluginsConfig, (declaration, pluginName) => {
81
81
  validatePluginName(pluginName);
82
- declaredPlugins[pluginName] = toDetailedDeclaration(declaration);
82
+
83
+ declaredPlugins[pluginName] = {
84
+ ...toDetailedDeclaration(declaration),
85
+ info: {},
86
+ };
87
+
88
+ const { pathToPlugin } = declaredPlugins[pluginName];
89
+
90
+ // for manually resolved plugins
91
+ if (pathToPlugin) {
92
+ const packagePath = join(pathToPlugin, 'package.json');
93
+ const packageInfo = require(packagePath);
94
+
95
+ if (isStrapiPlugin(packageInfo)) {
96
+ declaredPlugins[pluginName].info = packageInfo.strapi || {};
97
+ }
98
+ }
83
99
  });
84
100
 
85
101
  const declaredPluginsResolves = map(prop('pathToPlugin'), declaredPlugins);
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { join } = require('path');
4
- const { existsSync } = require('fs');
4
+ const fse = require('fs-extra');
5
5
  const { defaultsDeep, getOr, get } = require('lodash/fp');
6
6
  const { env } = require('@strapi/utils');
7
7
  const loadConfigFile = require('../../app-configuration/load-config-file');
@@ -26,7 +26,7 @@ const defaultPlugin = {
26
26
 
27
27
  const applyUserExtension = async plugins => {
28
28
  const extensionsDir = strapi.dirs.extensions;
29
- if (!existsSync(extensionsDir)) {
29
+ if (!(await fse.pathExists(extensionsDir))) {
30
30
  return;
31
31
  }
32
32
 
@@ -61,9 +61,9 @@ const formatContentTypes = plugins => {
61
61
  }
62
62
  };
63
63
 
64
- const applyUserConfig = plugins => {
64
+ const applyUserConfig = async plugins => {
65
65
  const userPluginConfigPath = join(strapi.dirs.config, 'plugins.js');
66
- const userPluginsConfig = existsSync(userPluginConfigPath)
66
+ const userPluginsConfig = (await fse.pathExists(userPluginConfigPath))
67
67
  ? loadConfigFile(userPluginConfigPath)
68
68
  : {};
69
69
 
@@ -90,14 +90,24 @@ const loadPlugins = async strapi => {
90
90
 
91
91
  const enabledPlugins = await getEnabledPlugins(strapi);
92
92
 
93
+ strapi.config.set('enabledPlugins', enabledPlugins);
94
+
93
95
  for (const pluginName in enabledPlugins) {
94
96
  const enabledPlugin = enabledPlugins[pluginName];
95
- const pluginServer = loadConfigFile(join(enabledPlugin.pathToPlugin, 'strapi-server.js'));
97
+
98
+ const serverEntrypointPath = join(enabledPlugin.pathToPlugin, 'strapi-server.js');
99
+
100
+ // only load plugins with a server entrypoint
101
+ if (!(await fse.pathExists(serverEntrypointPath))) {
102
+ continue;
103
+ }
104
+
105
+ const pluginServer = loadConfigFile(serverEntrypointPath);
96
106
  plugins[pluginName] = defaultsDeep(defaultPlugin, pluginServer);
97
107
  }
98
108
 
99
109
  // TODO: validate plugin format
100
- applyUserConfig(plugins);
110
+ await applyUserConfig(plugins);
101
111
  await applyUserExtension(plugins);
102
112
  formatContentTypes(plugins);
103
113
 
@@ -1,7 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  const { has } = require('lodash/fp');
4
- const { createCoreApi } = require('../../core-api');
5
4
 
6
5
  const apisRegistry = strapi => {
7
6
  const apis = {};
@@ -18,22 +17,9 @@ const apisRegistry = strapi => {
18
17
  throw new Error(`API ${apiName} has already been registered.`);
19
18
  }
20
19
 
21
- const apiInstance = strapi.container.get('modules').add(`api::${apiName}`, apiConfig);
20
+ const api = strapi.container.get('modules').add(`api::${apiName}`, apiConfig);
22
21
 
23
- for (const ctName in apiInstance.contentTypes || {}) {
24
- const contentType = apiInstance.contentTypes[ctName];
25
-
26
- const { service, controller } = createCoreApi({
27
- model: contentType,
28
- api: apiInstance,
29
- strapi,
30
- });
31
-
32
- strapi.container.get('services').set(`api::${apiName}.${ctName}`, service);
33
- strapi.container.get('controllers').set(`api::${apiName}.${ctName}`, controller);
34
- }
35
-
36
- apis[apiName] = apiInstance;
22
+ apis[apiName] = api;
37
23
 
38
24
  return apis[apiName];
39
25
  },
@@ -0,0 +1,7 @@
1
+ import { Strapi } from '../../';
2
+
3
+ export type Controller = {
4
+ [key: string]: (...args: any) => any;
5
+ };
6
+
7
+ export type ControllerFactory = ({ strapi: Strapi }) => Controller;
@@ -3,20 +3,80 @@
3
3
  const { pickBy, has } = require('lodash/fp');
4
4
  const { addNamespace, hasNamespace } = require('../utils');
5
5
 
6
+ /**
7
+ * @typedef {import('./controllers').Controller} Controller
8
+ * @typedef {import('./controllers').ControllerFactory} ControllerFactory
9
+ */
10
+
6
11
  const controllersRegistry = () => {
7
12
  const controllers = {};
13
+ const instances = {};
8
14
 
9
15
  return {
16
+ /**
17
+ * Returns this list of registered controllers uids
18
+ * @returns {string[]}
19
+ */
20
+ keys() {
21
+ return Object.keys(controllers);
22
+ },
23
+
24
+ /**
25
+ * Returns the instance of a controller. Instantiate the controller if not already done
26
+ * @param {string} uid
27
+ * @returns {Controller}
28
+ */
10
29
  get(uid) {
11
- return controllers[uid];
30
+ if (instances[uid]) {
31
+ return instances[uid];
32
+ }
33
+
34
+ const controller = controllers[uid];
35
+
36
+ if (controller) {
37
+ instances[uid] = typeof controller === 'function' ? controller({ strapi }) : controller;
38
+ return instances[uid];
39
+ }
12
40
  },
41
+
42
+ /**
43
+ * Returns a map with all the controller in a namespace
44
+ * @param {string} namespace
45
+ * @returns {{ [key: string]: Controller }}
46
+ */
13
47
  getAll(namespace) {
14
- return pickBy((_, uid) => hasNamespace(uid, namespace))(controllers);
48
+ const filteredControllers = pickBy((_, uid) => hasNamespace(uid, namespace))(controllers);
49
+
50
+ const map = {};
51
+ for (const uid in filteredControllers) {
52
+ Object.defineProperty(map, uid, {
53
+ enumerable: true,
54
+ get: () => {
55
+ return this.get(uid);
56
+ },
57
+ });
58
+ }
59
+
60
+ return map;
15
61
  },
62
+
63
+ /**
64
+ * Registers a controller
65
+ * @param {string} uid
66
+ * @param {Controller} controller
67
+ */
16
68
  set(uid, value) {
17
69
  controllers[uid] = value;
70
+ delete instances[uid];
18
71
  return this;
19
72
  },
73
+
74
+ /**
75
+ * Registers a map of controllers for a specific namespace
76
+ * @param {string} namespace
77
+ * @param {{ [key: string]: Controller|ControllerFactory }} newControllers
78
+ * @returns
79
+ */
20
80
  add(namespace, newControllers) {
21
81
  for (const controllerName in newControllers) {
22
82
  const controller = newControllers[controllerName];
@@ -27,15 +87,26 @@ const controllersRegistry = () => {
27
87
  }
28
88
  controllers[uid] = controller;
29
89
  }
90
+
30
91
  return this;
31
92
  },
93
+
94
+ /**
95
+ * Wraps a controller to extend it
96
+ * @param {string} uid
97
+ * @param {(controller: Controller) => Controller} extendFn
98
+ */
32
99
  extend(controllerUID, extendFn) {
33
100
  const currentController = this.get(controllerUID);
101
+
34
102
  if (!currentController) {
35
103
  throw new Error(`Controller ${controllerUID} doesn't exist`);
36
104
  }
105
+
37
106
  const newController = extendFn(currentController);
38
- controllers[controllerUID] = newController;
107
+ instances[controllerUID] = newController;
108
+
109
+ return this;
39
110
  },
40
111
  };
41
112
  };
@@ -1,6 +1,5 @@
1
1
  'use strict';
2
2
 
3
- const _ = require('lodash');
4
3
  const { pickBy, has } = require('lodash/fp');
5
4
  const { addNamespace, hasNamespace } = require('../utils');
6
5
 
@@ -37,8 +36,6 @@ const servicesRegistry = strapi => {
37
36
  instantiatedServices[uid] = typeof service === 'function' ? service({ strapi }) : service;
38
37
  return instantiatedServices[uid];
39
38
  }
40
-
41
- return undefined;
42
39
  },
43
40
 
44
41
  /**
@@ -49,16 +46,28 @@ const servicesRegistry = strapi => {
49
46
  getAll(namespace) {
50
47
  const filteredServices = pickBy((_, uid) => hasNamespace(uid, namespace))(services);
51
48
 
52
- return _.mapValues(filteredServices, (service, serviceUID) => this.get(serviceUID));
49
+ // create lazy accessor to avoid instantiating the services;
50
+ const map = {};
51
+ for (const uid in filteredServices) {
52
+ Object.defineProperty(map, uid, {
53
+ enumerable: true,
54
+ get: () => {
55
+ return this.get(uid);
56
+ },
57
+ });
58
+ }
59
+
60
+ return map;
53
61
  },
54
62
 
55
63
  /**
56
64
  * Registers a service
57
65
  * @param {string} uid
58
- * @param {Service|ServiceFactory} service
66
+ * @param {Service} service
59
67
  */
60
68
  set(uid, service) {
61
- instantiatedServices[uid] = service;
69
+ services[uid] = service;
70
+ delete instantiatedServices[uid];
62
71
  return this;
63
72
  },
64
73
 
@@ -1,17 +1,17 @@
1
1
  'use strict';
2
2
 
3
+ const { isObject } = require('lodash/fp');
4
+ const { ValidationError } = require('@strapi/utils').errors;
5
+
3
6
  const { parseBody } = require('./transform');
4
7
 
5
8
  /**
6
9
  *
7
10
  * Returns a collection type controller to handle default core-api actions
8
11
  */
9
- const createCollectionTypeController = ({
10
- service,
11
- sanitizeInput,
12
- sanitizeOutput,
13
- transformResponse,
14
- }) => {
12
+ const createCollectionTypeController = ({ contentType }) => {
13
+ const { uid } = contentType;
14
+
15
15
  return {
16
16
  /**
17
17
  * Retrieve records.
@@ -21,10 +21,10 @@ const createCollectionTypeController = ({
21
21
  async find(ctx) {
22
22
  const { query } = ctx;
23
23
 
24
- const { results, pagination } = await service.find(query);
25
- const sanitizedResults = await sanitizeOutput(results, ctx);
24
+ const { results, pagination } = await strapi.service(uid).find(query);
25
+ const sanitizedResults = await this.sanitizeOutput(results, ctx);
26
26
 
27
- return transformResponse(sanitizedResults, { pagination });
27
+ return this.transformResponse(sanitizedResults, { pagination });
28
28
  },
29
29
 
30
30
  /**
@@ -36,10 +36,10 @@ const createCollectionTypeController = ({
36
36
  const { id } = ctx.params;
37
37
  const { query } = ctx;
38
38
 
39
- const entity = await service.findOne(id, query);
40
- const sanitizedEntity = await sanitizeOutput(entity, ctx);
39
+ const entity = await strapi.service(uid).findOne(id, query);
40
+ const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
41
41
 
42
- return transformResponse(sanitizedEntity);
42
+ return this.transformResponse(sanitizedEntity);
43
43
  },
44
44
 
45
45
  /**
@@ -51,12 +51,19 @@ const createCollectionTypeController = ({
51
51
  const { query } = ctx.request;
52
52
 
53
53
  const { data, files } = parseBody(ctx);
54
- const sanitizedInputData = await sanitizeInput(data, ctx);
55
54
 
56
- const entity = await service.create({ ...query, data: sanitizedInputData, files });
57
- const sanitizedEntity = await sanitizeOutput(entity, ctx);
55
+ if (!isObject(data)) {
56
+ throw new ValidationError('Missing "data" payload in the request body');
57
+ }
58
+
59
+ const sanitizedInputData = await this.sanitizeInput(data, ctx);
58
60
 
59
- return transformResponse(sanitizedEntity);
61
+ const entity = await strapi
62
+ .service(uid)
63
+ .create({ ...query, data: sanitizedInputData, files });
64
+ const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
65
+
66
+ return this.transformResponse(sanitizedEntity);
60
67
  },
61
68
 
62
69
  /**
@@ -69,12 +76,19 @@ const createCollectionTypeController = ({
69
76
  const { query } = ctx.request;
70
77
 
71
78
  const { data, files } = parseBody(ctx);
72
- const sanitizedInputData = await sanitizeInput(data, ctx);
73
79
 
74
- const entity = await service.update(id, { ...query, data: sanitizedInputData, files });
75
- const sanitizedEntity = await sanitizeOutput(entity, ctx);
80
+ if (!isObject(data)) {
81
+ throw new ValidationError('Missing "data" payload in the request body');
82
+ }
83
+
84
+ const sanitizedInputData = await this.sanitizeInput(data, ctx);
85
+
86
+ const entity = await strapi
87
+ .service(uid)
88
+ .update(id, { ...query, data: sanitizedInputData, files });
89
+ const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
76
90
 
77
- return transformResponse(sanitizedEntity);
91
+ return this.transformResponse(sanitizedEntity);
78
92
  },
79
93
 
80
94
  /**
@@ -86,10 +100,10 @@ const createCollectionTypeController = ({
86
100
  const { id } = ctx.params;
87
101
  const { query } = ctx;
88
102
 
89
- const entity = await service.delete(id, query);
90
- const sanitizedEntity = await sanitizeOutput(entity, ctx);
103
+ const entity = await strapi.service(uid).delete(id, query);
104
+ const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
91
105
 
92
- return transformResponse(sanitizedEntity);
106
+ return this.transformResponse(sanitizedEntity);
93
107
  },
94
108
  };
95
109
  };
@@ -0,0 +1,25 @@
1
+ import { Context } from 'koa';
2
+
3
+ type Response = object;
4
+
5
+ interface BaseController {
6
+ transformResponse(data: object, meta: object): object;
7
+ sanitizeOutput(data: object, ctx: Context): Promise<object>;
8
+ sanitizeInput(data: object, ctx: Context): Promise<object>;
9
+ }
10
+
11
+ export interface SingleTypeController extends BaseController {
12
+ find(ctx: Context): Promise<Response>;
13
+ update(ctx: Context): Promise<Response>;
14
+ delete(ctx: Context): Promise<Response>;
15
+ }
16
+
17
+ export interface CollectionTypeController extends BaseController {
18
+ find(ctx: Context): Promise<Response>;
19
+ findOne(ctx: Context): Promise<Response>;
20
+ create(ctx: Context): Promise<Response>;
21
+ update(ctx: Context): Promise<Response>;
22
+ delete(ctx: Context): Promise<Response>;
23
+ }
24
+
25
+ export type Controller = SingleTypeController | CollectionTypeController;
@@ -10,31 +10,36 @@ const createCollectionTypeController = require('./collection-type');
10
10
 
11
11
  const getAuthFromKoaContext = getOr({}, 'state.auth');
12
12
 
13
- module.exports = ({ service, model }) => {
14
- const ctx = {
15
- model,
16
- service,
13
+ const createController = ({ contentType }) => {
14
+ const ctx = { contentType };
17
15
 
16
+ const proto = {
18
17
  transformResponse(data, meta) {
19
- return transformResponse(data, meta, { contentType: model });
18
+ return transformResponse(data, meta, { contentType });
20
19
  },
21
20
 
22
21
  sanitizeOutput(data, ctx) {
23
22
  const auth = getAuthFromKoaContext(ctx);
24
23
 
25
- return sanitize.contentAPI.output(data, strapi.getModel(model.uid), { auth });
24
+ return sanitize.contentAPI.output(data, contentType, { auth });
26
25
  },
27
26
 
28
27
  sanitizeInput(data, ctx) {
29
28
  const auth = getAuthFromKoaContext(ctx);
30
29
 
31
- return sanitize.contentAPI.input(data, strapi.getModel(model.uid), { auth });
30
+ return sanitize.contentAPI.input(data, contentType, { auth });
32
31
  },
33
32
  };
34
33
 
35
- if (contentTypes.isSingleType(model)) {
36
- return createSingleTypeController(ctx);
34
+ let ctrl;
35
+
36
+ if (contentTypes.isSingleType(contentType)) {
37
+ ctrl = createSingleTypeController(ctx);
38
+ } else {
39
+ ctrl = createCollectionTypeController(ctx);
37
40
  }
38
41
 
39
- return createCollectionTypeController(ctx);
42
+ return Object.assign(Object.create(proto), ctrl);
40
43
  };
44
+
45
+ module.exports = { createController };
@@ -1,16 +1,16 @@
1
1
  'use strict';
2
2
 
3
+ const { isObject } = require('lodash/fp');
4
+ const { ValidationError } = require('@strapi/utils').errors;
5
+
3
6
  const { parseBody } = require('./transform');
4
7
 
5
8
  /**
6
9
  * Returns a single type controller to handle default core-api actions
7
10
  */
8
- const createSingleTypeController = ({
9
- service,
10
- sanitizeInput,
11
- sanitizeOutput,
12
- transformResponse,
13
- }) => {
11
+ const createSingleTypeController = ({ contentType }) => {
12
+ const { uid } = contentType;
13
+
14
14
  return {
15
15
  /**
16
16
  * Retrieve single type content
@@ -20,10 +20,10 @@ const createSingleTypeController = ({
20
20
  async find(ctx) {
21
21
  const { query } = ctx;
22
22
 
23
- const entity = await service.find(query);
24
- const sanitizedEntity = await sanitizeOutput(entity, ctx);
23
+ const entity = await strapi.service(uid).find(query);
24
+ const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
25
25
 
26
- return transformResponse(sanitizedEntity);
26
+ return this.transformResponse(sanitizedEntity);
27
27
  },
28
28
 
29
29
  /**
@@ -34,21 +34,28 @@ const createSingleTypeController = ({
34
34
  async update(ctx) {
35
35
  const { query } = ctx.request;
36
36
  const { data, files } = parseBody(ctx);
37
- const sanitizedInputData = await sanitizeInput(data, ctx);
38
37
 
39
- const entity = await service.createOrUpdate({ ...query, data: sanitizedInputData, files });
40
- const sanitizedEntity = await sanitizeOutput(entity, ctx);
38
+ if (!isObject(data)) {
39
+ throw new ValidationError('Missing "data" payload in the request body');
40
+ }
41
+
42
+ const sanitizedInputData = await this.sanitizeInput(data, ctx);
43
+
44
+ const entity = await strapi
45
+ .service(uid)
46
+ .createOrUpdate({ ...query, data: sanitizedInputData, files });
47
+ const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
41
48
 
42
- return transformResponse(sanitizedEntity);
49
+ return this.transformResponse(sanitizedEntity);
43
50
  },
44
51
 
45
52
  async delete(ctx) {
46
53
  const { query } = ctx;
47
54
 
48
- const entity = await service.delete(query);
49
- const sanitizedEntity = await sanitizeOutput(entity, ctx);
55
+ const entity = await strapi.service(uid).delete(query);
56
+ const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
50
57
 
51
- return transformResponse(sanitizedEntity);
58
+ return this.transformResponse(sanitizedEntity);
52
59
  },
53
60
  };
54
61
  };