@strapi/strapi 4.0.0-next.9 → 4.0.3

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 (142) hide show
  1. package/README.md +14 -14
  2. package/bin/strapi.js +37 -6
  3. package/lib/Strapi.js +140 -72
  4. package/lib/commands/build.js +21 -11
  5. package/lib/commands/console.js +1 -1
  6. package/lib/commands/content-types/list.js +22 -0
  7. package/lib/commands/controllers/list.js +22 -0
  8. package/lib/commands/develop.js +24 -27
  9. package/lib/commands/generate-template.js +4 -5
  10. package/lib/commands/hooks/list.js +22 -0
  11. package/lib/commands/middlewares/list.js +22 -0
  12. package/lib/commands/new.js +3 -1
  13. package/lib/commands/policies/list.js +22 -0
  14. package/lib/commands/routes/list.js +28 -0
  15. package/lib/commands/services/list.js +22 -0
  16. package/lib/commands/watchAdmin.js +18 -9
  17. package/lib/core/app-configuration/index.js +3 -19
  18. package/lib/core/bootstrap.js +3 -34
  19. package/lib/core/domain/content-type/index.js +3 -7
  20. package/lib/core/domain/module/index.js +8 -6
  21. package/lib/core/domain/module/validation.js +1 -4
  22. package/lib/core/loaders/admin.js +2 -2
  23. package/lib/core/loaders/apis.js +7 -7
  24. package/lib/core/loaders/components.js +3 -5
  25. package/lib/core/loaders/index.js +1 -0
  26. package/lib/core/loaders/middlewares.js +23 -123
  27. package/lib/core/loaders/plugins/get-enabled-plugins.js +55 -19
  28. package/lib/core/loaders/plugins/get-user-plugins-config.js +37 -0
  29. package/lib/core/loaders/plugins/index.js +30 -16
  30. package/lib/core/loaders/policies.js +1 -1
  31. package/lib/core/loaders/src-index.js +39 -0
  32. package/lib/core/registries/apis.js +2 -16
  33. package/lib/core/registries/content-types.js +50 -6
  34. package/lib/core/registries/controllers.d.ts +7 -0
  35. package/lib/core/registries/controllers.js +74 -3
  36. package/lib/core/registries/hooks.d.ts +20 -0
  37. package/lib/core/registries/hooks.js +87 -0
  38. package/lib/core/registries/middlewares.d.ts +5 -0
  39. package/lib/core/registries/middlewares.js +61 -2
  40. package/lib/core/registries/modules.js +3 -3
  41. package/lib/core/registries/plugins.js +2 -2
  42. package/lib/core/registries/policies.d.ts +9 -0
  43. package/lib/core/registries/policies.js +57 -6
  44. package/lib/core/registries/services.d.ts +7 -0
  45. package/lib/core/registries/services.js +71 -15
  46. package/lib/core-api/controller/collection-type.js +38 -11
  47. package/lib/core-api/controller/index.d.ts +25 -0
  48. package/lib/core-api/controller/index.js +30 -11
  49. package/lib/core-api/controller/single-type.js +26 -7
  50. package/lib/core-api/controller/transform.js +28 -3
  51. package/lib/core-api/routes/index.js +71 -0
  52. package/lib/core-api/service/collection-type.js +22 -27
  53. package/lib/core-api/service/index.d.ts +21 -0
  54. package/lib/core-api/service/index.js +9 -19
  55. package/lib/core-api/service/pagination.js +16 -16
  56. package/lib/core-api/service/single-type.js +17 -20
  57. package/lib/factories.d.ts +48 -0
  58. package/lib/factories.js +84 -0
  59. package/lib/index.d.ts +10 -31
  60. package/lib/index.js +5 -1
  61. package/lib/middlewares/body.js +33 -0
  62. package/lib/middlewares/compression.js +8 -0
  63. package/lib/middlewares/cors.js +58 -0
  64. package/lib/middlewares/errors.js +40 -0
  65. package/lib/middlewares/favicon.js +19 -0
  66. package/lib/middlewares/index.d.ts +5 -0
  67. package/lib/middlewares/index.js +30 -116
  68. package/lib/middlewares/ip.js +8 -0
  69. package/lib/middlewares/logger.js +27 -0
  70. package/lib/middlewares/powered-by.js +20 -0
  71. package/lib/middlewares/public/index.js +72 -77
  72. package/lib/middlewares/query.js +46 -0
  73. package/lib/middlewares/response-time.js +15 -0
  74. package/lib/middlewares/responses.js +19 -0
  75. package/lib/middlewares/security.js +51 -0
  76. package/lib/middlewares/session/index.js +6 -6
  77. package/lib/migrations/draft-publish.js +57 -0
  78. package/lib/services/auth/index.js +87 -0
  79. package/lib/services/core-store.js +64 -49
  80. package/lib/services/cron.js +54 -0
  81. package/lib/services/entity-service/attributes/index.js +31 -0
  82. package/lib/services/entity-service/attributes/transforms.js +20 -0
  83. package/lib/services/entity-service/components.js +39 -15
  84. package/lib/services/entity-service/index.d.ts +91 -0
  85. package/lib/services/entity-service/index.js +118 -60
  86. package/lib/services/entity-service/params.js +48 -81
  87. package/lib/services/entity-validator/index.js +76 -43
  88. package/lib/services/entity-validator/validators.js +131 -43
  89. package/lib/services/errors.js +77 -0
  90. package/lib/services/fs.js +1 -1
  91. package/lib/services/metrics/index.js +38 -36
  92. package/lib/services/server/admin-api.js +14 -0
  93. package/lib/services/server/api.js +36 -0
  94. package/lib/services/server/compose-endpoint.js +141 -0
  95. package/lib/services/server/content-api.js +16 -0
  96. package/lib/{server.js → services/server/http-server.js} +0 -0
  97. package/lib/services/server/index.js +127 -0
  98. package/lib/services/server/koa.js +64 -0
  99. package/lib/services/server/middleware.js +122 -0
  100. package/lib/services/server/policy.js +32 -0
  101. package/lib/services/server/register-middlewares.js +110 -0
  102. package/lib/services/server/register-routes.js +106 -0
  103. package/lib/services/server/routing.js +120 -0
  104. package/lib/services/webhook-runner.js +1 -1
  105. package/lib/utils/ee.js +3 -3
  106. package/lib/utils/get-dirs.js +17 -0
  107. package/lib/utils/index.js +2 -0
  108. package/lib/utils/signals.js +24 -0
  109. package/lib/utils/update-notifier/index.js +2 -1
  110. package/package.json +94 -93
  111. package/lib/core/app-configuration/load-functions.js +0 -28
  112. package/lib/core-api/index.js +0 -39
  113. package/lib/middlewares/boom/defaults.json +0 -5
  114. package/lib/middlewares/boom/index.js +0 -147
  115. package/lib/middlewares/cors/index.js +0 -66
  116. package/lib/middlewares/cron/defaults.json +0 -5
  117. package/lib/middlewares/cron/index.js +0 -43
  118. package/lib/middlewares/favicon/defaults.json +0 -7
  119. package/lib/middlewares/favicon/index.js +0 -32
  120. package/lib/middlewares/gzip/defaults.json +0 -6
  121. package/lib/middlewares/gzip/index.js +0 -19
  122. package/lib/middlewares/helmet/defaults.json +0 -18
  123. package/lib/middlewares/helmet/index.js +0 -9
  124. package/lib/middlewares/ip/defaults.json +0 -7
  125. package/lib/middlewares/ip/index.js +0 -25
  126. package/lib/middlewares/language/defaults.json +0 -9
  127. package/lib/middlewares/language/index.js +0 -40
  128. package/lib/middlewares/logger/defaults.json +0 -5
  129. package/lib/middlewares/logger/index.js +0 -37
  130. package/lib/middlewares/parser/defaults.json +0 -11
  131. package/lib/middlewares/parser/index.js +0 -72
  132. package/lib/middlewares/poweredBy/defaults.json +0 -5
  133. package/lib/middlewares/poweredBy/index.js +0 -16
  134. package/lib/middlewares/public/defaults.json +0 -8
  135. package/lib/middlewares/responseTime/defaults.json +0 -5
  136. package/lib/middlewares/responseTime/index.js +0 -25
  137. package/lib/middlewares/responses/defaults.json +0 -5
  138. package/lib/middlewares/responses/index.js +0 -18
  139. package/lib/middlewares/router/defaults.json +0 -7
  140. package/lib/middlewares/router/index.js +0 -72
  141. package/lib/middlewares/router/utils/compose-endpoint.js +0 -169
  142. package/lib/utils/get-prefixed-dependencies.js +0 -7
@@ -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({ params: 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({ params: 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({ params: 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
  };
@@ -24,13 +24,28 @@ const transformResponse = (resource, meta = {}, { contentType } = {}) => {
24
24
  };
25
25
  };
26
26
 
27
- const transformEntry = (entry, contentType) => {
27
+ const transformComponent = (data, component) => {
28
+ if (Array.isArray(data)) {
29
+ return data.map(datum => transformComponent(datum, component));
30
+ }
31
+
32
+ const res = transformEntry(data, component);
33
+
34
+ if (isNil(res)) {
35
+ return res;
36
+ }
37
+
38
+ const { id, attributes } = res;
39
+ return { id, ...attributes };
40
+ };
41
+
42
+ const transformEntry = (entry, type) => {
28
43
  if (isNil(entry)) {
29
44
  return entry;
30
45
  }
31
46
 
32
47
  if (Array.isArray(entry)) {
33
- return entry.map(singleEntry => transformEntry(singleEntry, contentType));
48
+ return entry.map(singleEntry => transformEntry(singleEntry, type));
34
49
  }
35
50
 
36
51
  if (!isPlainObject(entry)) {
@@ -43,12 +58,22 @@ const transformEntry = (entry, contentType) => {
43
58
 
44
59
  for (const key in properties) {
45
60
  const property = properties[key];
46
- const attribute = contentType && contentType.attributes[key];
61
+ const attribute = type && type.attributes[key];
47
62
 
48
63
  if (attribute && attribute.type === 'relation') {
49
64
  const data = transformEntry(property, strapi.contentType(attribute.target));
50
65
 
51
66
  attributeValues[key] = { data };
67
+ } else if (attribute && attribute.type === 'component') {
68
+ attributeValues[key] = transformComponent(property, strapi.components[attribute.component]);
69
+ } else if (attribute && attribute.type === 'dynamiczone') {
70
+ if (isNil(property)) {
71
+ attributeValues[key] = property;
72
+ }
73
+
74
+ attributeValues[key] = property.map(subProperty => {
75
+ return transformComponent(subProperty, strapi.components[subProperty.__component]);
76
+ });
52
77
  } else if (attribute && attribute.type === 'media') {
53
78
  const data = transformEntry(property, strapi.contentType('plugin::upload.file'));
54
79
 
@@ -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,25 +22,22 @@ 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
- async find(opts = {}) {
32
- const params = getFetchParams(opts.params);
29
+ async find(params = {}) {
30
+ const fetchParams = this.getFetchParams(params);
33
31
 
34
- const paginationInfo = getPaginationInfo(params);
32
+ const paginationInfo = getPaginationInfo(fetchParams);
35
33
 
36
- const results = await strapi.entityService.find(uid, {
37
- params: { ...params, ...convertPagedToStartLimit(paginationInfo) },
34
+ const results = await strapi.entityService.findMany(uid, {
35
+ ...fetchParams,
36
+ ...convertPagedToStartLimit(paginationInfo),
38
37
  });
39
38
 
40
- if (shouldCount(params)) {
41
- const count = await strapi.entityService.count(uid, {
42
- params: { ...params, ...paginationInfo },
43
- });
39
+ if (shouldCount(fetchParams)) {
40
+ const count = await strapi.entityService.count(uid, { ...fetchParams, ...paginationInfo });
44
41
 
45
42
  return {
46
43
  results,
@@ -54,30 +51,28 @@ const createCollectionTypeService = ({ model, strapi, utils }) => {
54
51
  };
55
52
  },
56
53
 
57
- findOne(entityId, opts = {}) {
58
- const params = getFetchParams(opts.params);
59
-
60
- return strapi.entityService.findOne(uid, entityId, { params });
54
+ findOne(entityId, params = {}) {
55
+ return strapi.entityService.findOne(uid, entityId, this.getFetchParams(params));
61
56
  },
62
57
 
63
- create({ params, data, files } = {}) {
64
- const sanitizedData = sanitizeInput(data);
58
+ create(params = {}) {
59
+ const { data } = params;
65
60
 
66
- if (hasDraftAndPublish(model)) {
67
- setPublishedAt(sanitizedData);
61
+ if (hasDraftAndPublish(contentType)) {
62
+ setPublishedAt(data);
68
63
  }
69
64
 
70
- return strapi.entityService.create(uid, { params, data: sanitizedData, files });
65
+ return strapi.entityService.create(uid, { ...params, data });
71
66
  },
72
67
 
73
- update(entityId, { params, data, files } = {}) {
74
- const sanitizedData = sanitizeInput(data);
68
+ update(entityId, params = {}) {
69
+ const { data } = params;
75
70
 
76
- return strapi.entityService.update(uid, entityId, { params, data: sanitizedData, files });
71
+ return strapi.entityService.update(uid, entityId, { ...params, data });
77
72
  },
78
73
 
79
- delete(entityId, { params } = {}) {
80
- return strapi.entityService.delete(uid, entityId, { params });
74
+ delete(entityId, params = {}) {
75
+ return strapi.entityService.delete(uid, entityId, params);
81
76
  },
82
77
  };
83
78
  };
@@ -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
@@ -12,18 +13,13 @@ const getLimitConfigDefaults = () => ({
12
13
  });
13
14
 
14
15
  /**
15
- * if there is max limit set and limit exceeds this number, return configured max limit
16
+ * Should maxLimit be used as the limit or not
16
17
  * @param {number} limit - limit you want to cap
17
18
  * @param {number?} maxLimit - maxlimit used has capping
18
- * @returns {number}
19
+ * @returns {boolean}
19
20
  */
20
- const applyMaxLimit = (limit, maxLimit) => {
21
- if (maxLimit && (limit === -1 || limit > maxLimit)) {
22
- return maxLimit;
23
- }
24
-
25
- return limit;
26
- };
21
+ const shouldApplyMaxLimit = (limit, maxLimit = null, { isPagedPagination = false } = {}) =>
22
+ (!isPagedPagination && limit === -1) || (maxLimit && limit > maxLimit);
27
23
 
28
24
  const shouldCount = params => {
29
25
  if (has('pagination.withCount', params)) {
@@ -41,7 +37,9 @@ const shouldCount = params => {
41
37
  return false;
42
38
  }
43
39
 
44
- throw new Error('Invalid withCount parameter. Expected "t","1","true","false","0","f"');
40
+ throw new ValidationError(
41
+ 'Invalid withCount parameter. Expected "t","1","true","false","0","f"'
42
+ );
45
43
  }
46
44
 
47
45
  return Boolean(strapi.config.get('api.rest.withCount', true));
@@ -66,7 +64,9 @@ const getPaginationInfo = params => {
66
64
  }
67
65
 
68
66
  if (isOffset && isPaged) {
69
- throw new Error('Invalid pagination parameters. Expected either start/limit or page/pageSize');
67
+ throw new ValidationError(
68
+ 'Invalid pagination parameters. Expected either start/limit or page/pageSize'
69
+ );
70
70
  }
71
71
 
72
72
  if (isPagedPagination(pagination)) {
@@ -76,17 +76,17 @@ const getPaginationInfo = params => {
76
76
 
77
77
  return {
78
78
  page: Math.max(1, toNumber(pagination.page || 1)),
79
- pageSize: applyMaxLimit(pageSize, maxLimit),
79
+ pageSize: shouldApplyMaxLimit(pageSize, maxLimit, { isPagedPagination: true })
80
+ ? maxLimit
81
+ : Math.max(1, pageSize),
80
82
  };
81
83
  }
82
84
 
83
- const limit = isUndefined(pagination.limit)
84
- ? defaultLimit
85
- : Math.max(1, toNumber(pagination.limit));
85
+ const limit = isUndefined(pagination.limit) ? defaultLimit : toNumber(pagination.limit);
86
86
 
87
87
  return {
88
88
  start: Math.max(0, toNumber(pagination.start || 0)),
89
- limit: applyMaxLimit(limit, maxLimit),
89
+ limit: shouldApplyMaxLimit(limit, maxLimit) ? maxLimit || -1 : Math.max(1, limit),
90
90
  };
91
91
  };
92
92
 
@@ -1,21 +1,24 @@
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
13
17
  *
14
18
  * @return {Promise}
15
19
  */
16
- find({ params } = {}) {
17
- const normalizedParams = getFetchParams(params);
18
- return strapi.entityService.find(uid, { params: normalizedParams });
20
+ find(params = {}) {
21
+ return strapi.entityService.findMany(uid, this.getFetchParams(params));
19
22
  },
20
23
 
21
24
  /**
@@ -23,25 +26,19 @@ const createSingleTypeService = ({ model, strapi, utils }) => {
23
26
  *
24
27
  * @return {Promise}
25
28
  */
26
- async createOrUpdate({ params, data, files } = {}) {
27
- const entity = await this.find({ params });
28
-
29
- const sanitizedData = sanitizeInput(data);
29
+ async createOrUpdate({ data, ...params } = {}) {
30
+ const entity = await this.find(params);
30
31
 
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, files });
38
- } else {
39
- return strapi.entityService.update(uid, entity.id, {
40
- params,
41
- data: sanitizedData,
42
- files,
43
- });
38
+ return strapi.entityService.create(uid, { ...params, data });
44
39
  }
40
+
41
+ return strapi.entityService.update(uid, entity.id, { ...params, data });
45
42
  },
46
43
 
47
44
  /**
@@ -49,8 +46,8 @@ const createSingleTypeService = ({ model, strapi, utils }) => {
49
46
  *
50
47
  * @return {Promise}
51
48
  */
52
- async delete({ params } = {}) {
53
- const entity = await this.find({ params });
49
+ async delete(params = {}) {
50
+ const entity = await this.find(params);
54
51
 
55
52
  if (!entity) return;
56
53
 
@@ -0,0 +1,48 @@
1
+ import { Service } from './core-api/service';
2
+ import { Controller } from './core-api/controller';
3
+ import { Middleware } from './middlewares';
4
+ import { Policy } from './core/registries/policies';
5
+
6
+ type ControllerConfig = Controller;
7
+
8
+ type ServiceConfig = Service;
9
+
10
+ type HandlerConfig = {
11
+ auth: false | { scope: string[] };
12
+ policies: Array<string | Policy>;
13
+ middlewares: Array<string | Middleware>;
14
+ };
15
+
16
+ type SingleTypeRouterConfig = {
17
+ find: HandlerConfig;
18
+ update: HandlerConfig;
19
+ delete: HandlerConfig;
20
+ };
21
+
22
+ type CollectionTypeRouterConfig = {
23
+ find: HandlerConfig;
24
+ findOne: HandlerConfig;
25
+ create: HandlerConfig;
26
+ update: HandlerConfig;
27
+ delete: HandlerConfig;
28
+ };
29
+
30
+ type RouterConfig = {
31
+ prefix: string;
32
+ only: string[];
33
+ except: string[];
34
+ config: SingleTypeRouterConfig | CollectionTypeRouterConfig;
35
+ };
36
+
37
+ interface Route {
38
+ method: string;
39
+ path: string;
40
+ }
41
+ interface Router {
42
+ prefix: string;
43
+ routes: Route[];
44
+ }
45
+
46
+ export function createCoreRouter(uid: string, cfg: RouterConfig): () => Router;
47
+ export function createCoreController(uid: string, cfg: ControllerConfig): () => Controller;
48
+ export function createCoreService(uid: string, cfg: ServiceConfig): () => Service;
@@ -0,0 +1,84 @@
1
+ 'use strict';
2
+
3
+ const { pipe, omit, pick } = require('lodash/fp');
4
+
5
+ const { createController } = require('./core-api/controller');
6
+ const { createService } = require('./core-api/service');
7
+ const { createRoutes } = require('./core-api/routes');
8
+
9
+ const createCoreController = (uid, cfg = {}) => {
10
+ return ({ strapi }) => {
11
+ const baseController = createController({
12
+ contentType: strapi.contentType(uid),
13
+ });
14
+
15
+ let userCtrl = typeof cfg === 'function' ? cfg({ strapi }) : cfg;
16
+
17
+ for (const methodName of Object.keys(baseController)) {
18
+ if (userCtrl[methodName] === undefined) {
19
+ userCtrl[methodName] = baseController[methodName];
20
+ }
21
+ }
22
+
23
+ Object.setPrototypeOf(userCtrl, baseController);
24
+ return userCtrl;
25
+ };
26
+ };
27
+
28
+ const createCoreService = (uid, cfg = {}) => {
29
+ return ({ strapi }) => {
30
+ const baseService = createService({
31
+ contentType: strapi.contentType(uid),
32
+ });
33
+
34
+ let userService = typeof cfg === 'function' ? cfg({ strapi }) : cfg;
35
+
36
+ for (const methodName of Object.keys(baseService)) {
37
+ if (userService[methodName] === undefined) {
38
+ userService[methodName] = baseService[methodName];
39
+ }
40
+ }
41
+
42
+ Object.setPrototypeOf(userService, baseService);
43
+ return userService;
44
+ };
45
+ };
46
+
47
+ const createCoreRouter = (uid, cfg = {}) => {
48
+ const { prefix, config = {}, only, except } = cfg;
49
+ let routes;
50
+
51
+ return {
52
+ get prefix() {
53
+ return prefix;
54
+ },
55
+ get routes() {
56
+ if (!routes) {
57
+ const contentType = strapi.contentType(uid);
58
+
59
+ const defaultRoutes = createRoutes({ contentType });
60
+
61
+ Object.keys(defaultRoutes).forEach(routeName => {
62
+ const defaultRoute = defaultRoutes[routeName];
63
+
64
+ Object.assign(defaultRoute.config, config[routeName] || {});
65
+ });
66
+
67
+ const selectedRoutes = pipe(
68
+ routes => (except ? omit(except, routes) : routes),
69
+ routes => (only ? pick(only, routes) : routes)
70
+ )(defaultRoutes);
71
+
72
+ routes = Object.values(selectedRoutes);
73
+ }
74
+
75
+ return routes;
76
+ },
77
+ };
78
+ };
79
+
80
+ module.exports = {
81
+ createCoreController,
82
+ createCoreService,
83
+ createCoreRouter,
84
+ };