@strapi/strapi 4.0.0-beta.2 → 4.0.0-beta.20

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 (89) hide show
  1. package/README.md +12 -12
  2. package/bin/strapi.js +6 -1
  3. package/lib/Strapi.js +33 -21
  4. package/lib/commands/build.js +1 -1
  5. package/lib/commands/content-types/list.js +3 -5
  6. package/lib/commands/develop.js +8 -10
  7. package/lib/commands/generate-template.js +4 -5
  8. package/lib/commands/hooks/list.js +3 -5
  9. package/lib/commands/middlewares/list.js +3 -5
  10. package/lib/commands/new.js +3 -1
  11. package/lib/commands/policies/list.js +3 -5
  12. package/lib/commands/services/list.js +22 -0
  13. package/lib/commands/watchAdmin.js +4 -4
  14. package/lib/core/app-configuration/index.js +5 -10
  15. package/lib/core/bootstrap.js +2 -2
  16. package/lib/core/domain/module/index.js +3 -1
  17. package/lib/core/domain/module/validation.js +1 -4
  18. package/lib/core/loaders/admin.js +2 -2
  19. package/lib/core/loaders/apis.js +3 -1
  20. package/lib/core/loaders/plugins/get-enabled-plugins.js +25 -9
  21. package/lib/core/loaders/plugins/index.js +21 -7
  22. package/lib/core/loaders/src-index.js +1 -0
  23. package/lib/core/registries/apis.js +2 -16
  24. package/lib/core/registries/content-types.js +50 -6
  25. package/lib/core/registries/controllers.d.ts +7 -0
  26. package/lib/core/registries/controllers.js +74 -3
  27. package/lib/core/registries/hooks.d.ts +20 -0
  28. package/lib/core/registries/hooks.js +57 -7
  29. package/lib/core/registries/middlewares.d.ts +5 -0
  30. package/lib/core/registries/middlewares.js +61 -2
  31. package/lib/core/registries/policies.d.ts +9 -0
  32. package/lib/core/registries/policies.js +57 -6
  33. package/lib/core/registries/services.d.ts +7 -0
  34. package/lib/core/registries/services.js +67 -11
  35. package/lib/core-api/controller/collection-type.js +38 -11
  36. package/lib/core-api/controller/index.d.ts +25 -0
  37. package/lib/core-api/controller/index.js +30 -11
  38. package/lib/core-api/controller/single-type.js +26 -7
  39. package/lib/core-api/routes/index.js +71 -0
  40. package/lib/core-api/service/collection-type.js +8 -12
  41. package/lib/core-api/service/index.d.ts +21 -0
  42. package/lib/core-api/service/index.js +9 -19
  43. package/lib/core-api/service/pagination.js +7 -2
  44. package/lib/core-api/service/single-type.js +12 -11
  45. package/lib/factories.d.ts +48 -0
  46. package/lib/factories.js +84 -0
  47. package/lib/index.d.ts +1 -0
  48. package/lib/index.js +5 -1
  49. package/lib/middlewares/body.js +33 -0
  50. package/lib/middlewares/compression.js +1 -1
  51. package/lib/middlewares/cors.js +3 -2
  52. package/lib/middlewares/errors.js +24 -119
  53. package/lib/middlewares/favicon.js +3 -3
  54. package/lib/middlewares/index.d.ts +2 -1
  55. package/lib/middlewares/index.js +4 -2
  56. package/lib/middlewares/ip.js +1 -1
  57. package/lib/middlewares/logger.js +1 -1
  58. package/lib/middlewares/powered-by.js +4 -2
  59. package/lib/middlewares/public/index.js +4 -7
  60. package/lib/middlewares/query.js +46 -0
  61. package/lib/middlewares/responses.js +2 -2
  62. package/lib/middlewares/security.js +29 -3
  63. package/lib/middlewares/session/index.js +1 -1
  64. package/lib/services/auth/index.js +1 -6
  65. package/lib/services/entity-service/attributes/index.js +31 -0
  66. package/lib/services/entity-service/attributes/transforms.js +20 -0
  67. package/lib/services/entity-service/components.js +2 -3
  68. package/lib/services/entity-service/index.d.ts +1 -1
  69. package/lib/services/entity-service/index.js +83 -27
  70. package/lib/services/entity-service/params.js +37 -87
  71. package/lib/services/entity-validator/index.js +76 -43
  72. package/lib/services/entity-validator/validators.js +129 -43
  73. package/lib/services/errors.js +77 -0
  74. package/lib/services/metrics/index.js +37 -35
  75. package/lib/services/server/compose-endpoint.js +39 -11
  76. package/lib/services/server/content-api.js +1 -1
  77. package/lib/services/server/index.js +4 -9
  78. package/lib/services/server/koa.js +64 -0
  79. package/lib/services/server/middleware.js +8 -1
  80. package/lib/services/server/policy.js +8 -10
  81. package/lib/services/server/register-middlewares.js +7 -2
  82. package/lib/services/server/register-routes.js +1 -3
  83. package/lib/services/server/routing.js +13 -0
  84. package/lib/utils/get-dirs.js +1 -0
  85. package/lib/utils/signals.js +24 -0
  86. package/package.json +22 -17
  87. package/lib/core/app-configuration/load-functions.js +0 -28
  88. package/lib/core-api/index.js +0 -39
  89. package/lib/middlewares/request.js +0 -74
@@ -1,14 +1,31 @@
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
 
6
+ /**
7
+ * @typedef {import('./services').Service} Service
8
+ * @typedef {import('./services').ServiceFactory} ServiceFactory
9
+ */
10
+
7
11
  const servicesRegistry = strapi => {
8
12
  const services = {};
9
13
  const instantiatedServices = {};
10
14
 
11
15
  return {
16
+ /**
17
+ * Returns this list of registered services uids
18
+ * @returns {string[]}
19
+ */
20
+ keys() {
21
+ return Object.keys(services);
22
+ },
23
+
24
+ /**
25
+ * Returns the instance of a service. Instantiate the service if not already done
26
+ * @param {string} uid
27
+ * @returns {Service}
28
+ */
12
29
  get(uid) {
13
30
  if (instantiatedServices[uid]) {
14
31
  return instantiatedServices[uid];
@@ -16,21 +33,50 @@ const servicesRegistry = strapi => {
16
33
 
17
34
  const service = services[uid];
18
35
  if (service) {
19
- instantiatedServices[uid] = service({ strapi });
36
+ instantiatedServices[uid] = typeof service === 'function' ? service({ strapi }) : service;
20
37
  return instantiatedServices[uid];
21
38
  }
22
-
23
- return undefined;
24
39
  },
40
+
41
+ /**
42
+ * Returns a map with all the services in a namespace
43
+ * @param {string} namespace
44
+ * @returns {{ [key: string]: Service }}
45
+ */
25
46
  getAll(namespace) {
26
47
  const filteredServices = pickBy((_, uid) => hasNamespace(uid, namespace))(services);
27
48
 
28
- 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;
29
61
  },
30
- set(uid, value) {
31
- instantiatedServices[uid] = value;
62
+
63
+ /**
64
+ * Registers a service
65
+ * @param {string} uid
66
+ * @param {Service} service
67
+ */
68
+ set(uid, service) {
69
+ services[uid] = service;
70
+ delete instantiatedServices[uid];
32
71
  return this;
33
72
  },
73
+
74
+ /**
75
+ * Registers a map of services for a specific namespace
76
+ * @param {string} namespace
77
+ * @param {{ [key: string]: Service|ServiceFactory }} newServices
78
+ * @returns
79
+ */
34
80
  add(namespace, newServices) {
35
81
  for (const serviceName in newServices) {
36
82
  const service = newServices[serviceName];
@@ -44,13 +90,23 @@ const servicesRegistry = strapi => {
44
90
 
45
91
  return this;
46
92
  },
47
- extend(serviceUID, extendFn) {
48
- const currentService = this.get(serviceUID);
93
+
94
+ /**
95
+ * Wraps a service to extend it
96
+ * @param {string} uid
97
+ * @param {(service: Service) => Service} extendFn
98
+ */
99
+ extend(uid, extendFn) {
100
+ const currentService = this.get(uid);
101
+
49
102
  if (!currentService) {
50
- throw new Error(`Service ${serviceUID} doesn't exist`);
103
+ throw new Error(`Service ${uid} doesn't exist`);
51
104
  }
105
+
52
106
  const newService = extendFn(currentService);
53
- instantiatedServices[serviceUID] = newService;
107
+ instantiatedServices[uid] = newService;
108
+
109
+ return this;
54
110
  },
55
111
  };
56
112
  };
@@ -1,12 +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 = ({ service, sanitize, transformResponse }) => {
12
+ const createCollectionTypeController = ({ contentType }) => {
13
+ const { uid } = contentType;
14
+
10
15
  return {
11
16
  /**
12
17
  * Retrieve records.
@@ -16,9 +21,10 @@ const createCollectionTypeController = ({ service, sanitize, transformResponse }
16
21
  async find(ctx) {
17
22
  const { query } = ctx;
18
23
 
19
- const { results, pagination } = await service.find(query);
24
+ const { results, pagination } = await strapi.service(uid).find(query);
25
+ const sanitizedResults = await this.sanitizeOutput(results, ctx);
20
26
 
21
- return transformResponse(sanitize(results), { pagination });
27
+ return this.transformResponse(sanitizedResults, { pagination });
22
28
  },
23
29
 
24
30
  /**
@@ -30,9 +36,10 @@ const createCollectionTypeController = ({ service, sanitize, transformResponse }
30
36
  const { id } = ctx.params;
31
37
  const { query } = ctx;
32
38
 
33
- const entity = await service.findOne(id, query);
39
+ const entity = await strapi.service(uid).findOne(id, query);
40
+ const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
34
41
 
35
- return transformResponse(sanitize(entity));
42
+ return this.transformResponse(sanitizedEntity);
36
43
  },
37
44
 
38
45
  /**
@@ -45,9 +52,18 @@ const createCollectionTypeController = ({ service, sanitize, transformResponse }
45
52
 
46
53
  const { data, files } = parseBody(ctx);
47
54
 
48
- const entity = await service.create({ ...query, data, files });
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);
60
+
61
+ const entity = await strapi
62
+ .service(uid)
63
+ .create({ ...query, data: sanitizedInputData, files });
64
+ const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
49
65
 
50
- return transformResponse(sanitize(entity));
66
+ return this.transformResponse(sanitizedEntity);
51
67
  },
52
68
 
53
69
  /**
@@ -61,9 +77,18 @@ const createCollectionTypeController = ({ service, sanitize, transformResponse }
61
77
 
62
78
  const { data, files } = parseBody(ctx);
63
79
 
64
- const entity = await service.update(id, { ...query, data, files });
80
+ if (!isObject(data)) {
81
+ throw new ValidationError('Missing "data" payload in the request body');
82
+ }
65
83
 
66
- return transformResponse(sanitize(entity));
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);
90
+
91
+ return this.transformResponse(sanitizedEntity);
67
92
  },
68
93
 
69
94
  /**
@@ -75,8 +100,10 @@ const createCollectionTypeController = ({ service, sanitize, transformResponse }
75
100
  const { id } = ctx.params;
76
101
  const { query } = ctx;
77
102
 
78
- const entity = await service.delete(id, query);
79
- return transformResponse(sanitize(entity));
103
+ const entity = await strapi.service(uid).delete(id, query);
104
+ const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
105
+
106
+ return this.transformResponse(sanitizedEntity);
80
107
  },
81
108
  };
82
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;
@@ -1,26 +1,45 @@
1
1
  'use strict';
2
2
 
3
- const { sanitizeEntity, contentTypes } = require('@strapi/utils');
3
+ const { getOr } = require('lodash/fp');
4
+
5
+ const { contentTypes, sanitize } = require('@strapi/utils');
4
6
 
5
7
  const { transformResponse } = require('./transform');
6
8
  const createSingleTypeController = require('./single-type');
7
9
  const createCollectionTypeController = require('./collection-type');
8
10
 
9
- module.exports = ({ service, model }) => {
10
- const ctx = {
11
- model,
12
- service,
11
+ const getAuthFromKoaContext = getOr({}, 'state.auth');
12
+
13
+ const createController = ({ contentType }) => {
14
+ const ctx = { contentType };
15
+
16
+ const proto = {
13
17
  transformResponse(data, meta) {
14
- return transformResponse(data, meta, { contentType: model });
18
+ return transformResponse(data, meta, { contentType });
19
+ },
20
+
21
+ sanitizeOutput(data, ctx) {
22
+ const auth = getAuthFromKoaContext(ctx);
23
+
24
+ return sanitize.contentAPI.output(data, contentType, { auth });
15
25
  },
16
- sanitize(data) {
17
- return sanitizeEntity(data, { model: strapi.getModel(model.uid) });
26
+
27
+ sanitizeInput(data, ctx) {
28
+ const auth = getAuthFromKoaContext(ctx);
29
+
30
+ return sanitize.contentAPI.input(data, contentType, { auth });
18
31
  },
19
32
  };
20
33
 
21
- if (contentTypes.isSingleType(model)) {
22
- return createSingleTypeController(ctx);
34
+ let ctrl;
35
+
36
+ if (contentTypes.isSingleType(contentType)) {
37
+ ctrl = createSingleTypeController(ctx);
38
+ } else {
39
+ ctrl = createCollectionTypeController(ctx);
23
40
  }
24
41
 
25
- return createCollectionTypeController(ctx);
42
+ return Object.assign(Object.create(proto), ctrl);
26
43
  };
44
+
45
+ module.exports = { createController };
@@ -1,11 +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 = ({ service, sanitize, transformResponse }) => {
11
+ const createSingleTypeController = ({ contentType }) => {
12
+ const { uid } = contentType;
13
+
9
14
  return {
10
15
  /**
11
16
  * Retrieve single type content
@@ -14,8 +19,11 @@ const createSingleTypeController = ({ service, sanitize, transformResponse }) =>
14
19
  */
15
20
  async find(ctx) {
16
21
  const { query } = ctx;
17
- const entity = await service.find(query);
18
- return transformResponse(sanitize(entity));
22
+
23
+ const entity = await strapi.service(uid).find(query);
24
+ const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
25
+
26
+ return this.transformResponse(sanitizedEntity);
19
27
  },
20
28
 
21
29
  /**
@@ -27,16 +35,27 @@ const createSingleTypeController = ({ service, sanitize, transformResponse }) =>
27
35
  const { query } = ctx.request;
28
36
  const { data, files } = parseBody(ctx);
29
37
 
30
- const entity = await service.createOrUpdate({ ...query, data, files });
38
+ if (!isObject(data)) {
39
+ throw new ValidationError('Missing "data" payload in the request body');
40
+ }
31
41
 
32
- return transformResponse(sanitize(entity));
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);
48
+
49
+ return this.transformResponse(sanitizedEntity);
33
50
  },
34
51
 
35
52
  async delete(ctx) {
36
53
  const { query } = ctx;
37
54
 
38
- const entity = await service.delete(query);
39
- return transformResponse(sanitize(entity));
55
+ const entity = await strapi.service(uid).delete(query);
56
+ const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
57
+
58
+ return this.transformResponse(sanitizedEntity);
40
59
  },
41
60
  };
42
61
  };
@@ -0,0 +1,71 @@
1
+ 'use strict';
2
+
3
+ const { isSingleType } = require('@strapi/utils').contentTypes;
4
+
5
+ const createRoutes = ({ contentType }) => {
6
+ if (isSingleType(contentType)) {
7
+ return getSingleTypeRoutes(contentType);
8
+ }
9
+
10
+ return getCollectionTypeRoutes(contentType);
11
+ };
12
+
13
+ const getSingleTypeRoutes = ({ uid, info }) => {
14
+ return {
15
+ find: {
16
+ method: 'GET',
17
+ path: `/${info.singularName}`,
18
+ handler: `${uid}.find`,
19
+ config: {},
20
+ },
21
+ update: {
22
+ method: 'PUT',
23
+ path: `/${info.singularName}`,
24
+ handler: `${uid}.update`,
25
+ config: {},
26
+ },
27
+ delete: {
28
+ method: 'DELETE',
29
+ path: `/${info.singularName}`,
30
+ handler: `${uid}.delete`,
31
+ config: {},
32
+ },
33
+ };
34
+ };
35
+
36
+ const getCollectionTypeRoutes = ({ uid, info }) => {
37
+ return {
38
+ find: {
39
+ method: 'GET',
40
+ path: `/${info.pluralName}`,
41
+ handler: `${uid}.find`,
42
+ config: {},
43
+ },
44
+ findOne: {
45
+ method: 'GET',
46
+ path: `/${info.pluralName}/:id`,
47
+ handler: `${uid}.findOne`,
48
+ config: {},
49
+ },
50
+ create: {
51
+ method: 'POST',
52
+ path: `/${info.pluralName}`,
53
+ handler: `${uid}.create`,
54
+ config: {},
55
+ },
56
+ update: {
57
+ method: 'PUT',
58
+ path: `/${info.pluralName}/:id`,
59
+ handler: `${uid}.update`,
60
+ config: {},
61
+ },
62
+ delete: {
63
+ method: 'DELETE',
64
+ path: `/${info.pluralName}/:id`,
65
+ handler: `${uid}.delete`,
66
+ config: {},
67
+ },
68
+ };
69
+ };
70
+
71
+ module.exports = { createRoutes };
@@ -22,14 +22,12 @@ const setPublishedAt = data => {
22
22
  *
23
23
  * Returns a collection type service to handle default core-api actions
24
24
  */
25
- const createCollectionTypeService = ({ model, strapi, utils }) => {
26
- const { uid } = model;
27
-
28
- const { sanitizeInput, getFetchParams } = utils;
25
+ const createCollectionTypeService = ({ contentType }) => {
26
+ const { uid } = contentType;
29
27
 
30
28
  return {
31
29
  async find(params = {}) {
32
- const fetchParams = getFetchParams(params);
30
+ const fetchParams = this.getFetchParams(params);
33
31
 
34
32
  const paginationInfo = getPaginationInfo(fetchParams);
35
33
 
@@ -54,25 +52,23 @@ const createCollectionTypeService = ({ model, strapi, utils }) => {
54
52
  },
55
53
 
56
54
  findOne(entityId, params = {}) {
57
- return strapi.entityService.findOne(uid, entityId, getFetchParams(params));
55
+ return strapi.entityService.findOne(uid, entityId, this.getFetchParams(params));
58
56
  },
59
57
 
60
58
  create(params = {}) {
61
59
  const { data } = params;
62
- const sanitizedData = sanitizeInput(data);
63
60
 
64
- if (hasDraftAndPublish(model)) {
65
- setPublishedAt(sanitizedData);
61
+ if (hasDraftAndPublish(contentType)) {
62
+ setPublishedAt(data);
66
63
  }
67
64
 
68
- return strapi.entityService.create(uid, { ...params, data: sanitizedData });
65
+ return strapi.entityService.create(uid, { ...params, data });
69
66
  },
70
67
 
71
68
  update(entityId, params = {}) {
72
69
  const { data } = params;
73
- const sanitizedData = sanitizeInput(data);
74
70
 
75
- return strapi.entityService.update(uid, entityId, { ...params, data: sanitizedData });
71
+ return strapi.entityService.update(uid, entityId, { ...params, data });
76
72
  },
77
73
 
78
74
  delete(entityId, params = {}) {
@@ -0,0 +1,21 @@
1
+ type Entity = object;
2
+
3
+ interface BaseService {
4
+ getFetchParams(params: object): object;
5
+ }
6
+
7
+ export interface SingleTypeService extends BaseService {
8
+ find(params: object): Promise<Entity>;
9
+ createOrUpdate(params: object): Promise<Entity>;
10
+ delete(params: object): Promise<Entity>;
11
+ }
12
+
13
+ export interface CollectionTypeService extends BaseService {
14
+ find(params: object): Promise<Entity[]>;
15
+ findOne(params: object): Promise<Entity>;
16
+ create(params: object): Promise<Entity>;
17
+ update(params: object): Promise<Entity>;
18
+ delete(params: object): Promise<Entity>;
19
+ }
20
+
21
+ export type Service = SingleTypeService | CollectionTypeService;
@@ -1,10 +1,7 @@
1
1
  'use strict';
2
2
 
3
- const _ = require('lodash');
4
-
5
3
  const {
6
4
  isSingleType,
7
- getNonWritableAttributes,
8
5
  constants: { DP_PUB_STATE_LIVE },
9
6
  } = require('@strapi/utils').contentTypes;
10
7
 
@@ -16,14 +13,18 @@ const createCollectionTypeService = require('./collection-type');
16
13
  * @param {{ model: object, strapi: object }} context
17
14
  * @returns {object}
18
15
  */
19
- const createService = ({ model, strapi }) => {
20
- const utils = createUtils({ model });
16
+ const createService = ({ contentType }) => {
17
+ const proto = { getFetchParams };
18
+
19
+ let service;
21
20
 
22
- if (isSingleType(model)) {
23
- return createSingleTypeService({ model, strapi, utils });
21
+ if (isSingleType(contentType)) {
22
+ service = createSingleTypeService({ contentType });
23
+ } else {
24
+ service = createCollectionTypeService({ contentType });
24
25
  }
25
26
 
26
- return createCollectionTypeService({ model, strapi, utils });
27
+ return Object.assign(Object.create(proto), service);
27
28
  };
28
29
 
29
30
  /**
@@ -38,17 +39,6 @@ const getFetchParams = (params = {}) => {
38
39
  };
39
40
  };
40
41
 
41
- /**
42
- * Mixins
43
- */
44
- const createUtils = ({ model }) => {
45
- return {
46
- // make sure to keep the call to getNonWritableAttributes dynamic
47
- sanitizeInput: data => _.omit(data, getNonWritableAttributes(model)),
48
- getFetchParams,
49
- };
50
- };
51
-
52
42
  module.exports = {
53
43
  createService,
54
44
  getFetchParams,
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { has, toNumber, isUndefined } = require('lodash/fp');
4
+ const { ValidationError } = require('@strapi/utils').errors;
4
5
 
5
6
  /**
6
7
  * Default limit values from config
@@ -41,7 +42,9 @@ const shouldCount = params => {
41
42
  return false;
42
43
  }
43
44
 
44
- throw new Error('Invalid withCount parameter. Expected "t","1","true","false","0","f"');
45
+ throw new ValidationError(
46
+ 'Invalid withCount parameter. Expected "t","1","true","false","0","f"'
47
+ );
45
48
  }
46
49
 
47
50
  return Boolean(strapi.config.get('api.rest.withCount', true));
@@ -66,7 +69,9 @@ const getPaginationInfo = params => {
66
69
  }
67
70
 
68
71
  if (isOffset && isPaged) {
69
- throw new Error('Invalid pagination parameters. Expected either start/limit or page/pageSize');
72
+ throw new ValidationError(
73
+ 'Invalid pagination parameters. Expected either start/limit or page/pageSize'
74
+ );
70
75
  }
71
76
 
72
77
  if (isPagedPagination(pagination)) {
@@ -1,12 +1,16 @@
1
1
  'use strict';
2
2
 
3
+ const { ValidationError } = require('@strapi/utils').errors;
4
+
3
5
  /**
4
6
  * Returns a single type service to handle default core-api actions
5
7
  */
6
- const createSingleTypeService = ({ model, strapi, utils }) => {
7
- const { uid } = model;
8
- const { sanitizeInput, getFetchParams } = utils;
8
+ const createSingleTypeService = ({ contentType }) => {
9
+ const { uid } = contentType;
9
10
 
11
+ /**
12
+ * @type {import('./').SingleTypeService}
13
+ */
10
14
  return {
11
15
  /**
12
16
  * Returns singleType content
@@ -14,7 +18,7 @@ const createSingleTypeService = ({ model, strapi, utils }) => {
14
18
  * @return {Promise}
15
19
  */
16
20
  find(params = {}) {
17
- return strapi.entityService.findMany(uid, getFetchParams(params));
21
+ return strapi.entityService.findMany(uid, this.getFetchParams(params));
18
22
  },
19
23
 
20
24
  /**
@@ -22,22 +26,19 @@ const createSingleTypeService = ({ model, strapi, utils }) => {
22
26
  *
23
27
  * @return {Promise}
24
28
  */
25
- async createOrUpdate(params = {}) {
29
+ async createOrUpdate({ data, ...params } = {}) {
26
30
  const entity = await this.find(params);
27
31
 
28
- const { data } = params;
29
- const sanitizedData = sanitizeInput(data);
30
-
31
32
  if (!entity) {
32
33
  const count = await strapi.query(uid).count();
33
34
  if (count >= 1) {
34
- throw strapi.errors.badRequest('singleType.alreadyExists');
35
+ throw new ValidationError('singleType.alreadyExists');
35
36
  }
36
37
 
37
- return strapi.entityService.create(uid, { ...params, data: sanitizedData });
38
+ return strapi.entityService.create(uid, { ...params, data });
38
39
  }
39
40
 
40
- return strapi.entityService.update(uid, entity.id, { ...params, data: sanitizedData });
41
+ return strapi.entityService.update(uid, entity.id, { ...params, data });
41
42
  },
42
43
 
43
44
  /**