@strapi/plugin-graphql 4.0.0-next.9 → 4.0.0

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 (122) hide show
  1. package/README.md +1 -1
  2. package/admin/src/index.js +0 -8
  3. package/package.json +39 -34
  4. package/server/bootstrap.js +148 -0
  5. package/server/config/default-config.js +13 -0
  6. package/server/config/index.js +7 -0
  7. package/server/format-graphql-error.js +50 -0
  8. package/server/services/builders/dynamic-zones.js +97 -0
  9. package/server/services/builders/entity-meta.js +7 -0
  10. package/server/services/builders/entity.js +43 -0
  11. package/server/services/builders/enums.js +24 -0
  12. package/server/services/builders/filters/content-type.js +93 -0
  13. package/server/services/builders/filters/index.js +7 -0
  14. package/server/services/builders/filters/operators/and.js +15 -0
  15. package/server/services/builders/filters/operators/between.js +15 -0
  16. package/server/services/builders/filters/operators/contains.js +13 -0
  17. package/server/services/builders/filters/operators/containsi.js +13 -0
  18. package/server/services/builders/filters/operators/ends-with.js +13 -0
  19. package/server/services/builders/filters/operators/eq.js +23 -0
  20. package/server/services/builders/filters/operators/gt.js +13 -0
  21. package/server/services/builders/filters/operators/gte.js +13 -0
  22. package/server/services/builders/filters/operators/in.js +15 -0
  23. package/server/services/builders/filters/operators/index.js +38 -0
  24. package/server/services/builders/filters/operators/lt.js +13 -0
  25. package/server/services/builders/filters/operators/lte.js +13 -0
  26. package/server/services/builders/filters/operators/ne.js +13 -0
  27. package/server/services/builders/filters/operators/not-contains.js +13 -0
  28. package/server/services/builders/filters/operators/not-containsi.js +13 -0
  29. package/server/services/builders/filters/operators/not-in.js +15 -0
  30. package/server/services/builders/filters/operators/not-null.js +13 -0
  31. package/server/services/builders/filters/operators/not.js +19 -0
  32. package/server/services/builders/filters/operators/null.js +13 -0
  33. package/server/services/builders/filters/operators/or.js +15 -0
  34. package/server/services/builders/filters/operators/starts-with.js +13 -0
  35. package/server/services/builders/generic-morph.js +41 -0
  36. package/server/services/builders/index.js +92 -0
  37. package/server/services/builders/input.js +121 -0
  38. package/server/services/builders/mutations/collection-type.js +191 -0
  39. package/server/services/builders/mutations/index.js +9 -0
  40. package/server/services/builders/mutations/single-type.js +141 -0
  41. package/server/services/builders/queries/collection-type.js +120 -0
  42. package/server/services/builders/queries/index.js +9 -0
  43. package/server/services/builders/queries/single-type.js +70 -0
  44. package/server/services/builders/relation-response-collection.js +35 -0
  45. package/server/services/builders/resolvers/association.js +85 -0
  46. package/server/services/builders/resolvers/component.js +18 -0
  47. package/server/services/builders/resolvers/dynamic-zone.js +9 -0
  48. package/server/services/builders/resolvers/index.js +18 -0
  49. package/server/services/builders/resolvers/mutation.js +33 -0
  50. package/server/services/builders/resolvers/query.js +19 -0
  51. package/server/services/builders/response-collection.js +43 -0
  52. package/server/services/builders/response.js +32 -0
  53. package/server/services/builders/type.js +364 -0
  54. package/server/services/builders/utils.js +134 -0
  55. package/server/services/constants.js +147 -0
  56. package/server/services/content-api/index.js +179 -0
  57. package/server/services/content-api/policy.js +60 -0
  58. package/server/services/content-api/register-functions/collection-type.js +72 -0
  59. package/server/services/content-api/register-functions/component.js +15 -0
  60. package/server/services/content-api/register-functions/content-type/dynamic-zones.js +36 -0
  61. package/server/services/content-api/register-functions/content-type/enums.js +33 -0
  62. package/server/services/content-api/register-functions/content-type/filters.js +15 -0
  63. package/server/services/content-api/register-functions/content-type/index.js +13 -0
  64. package/server/services/content-api/register-functions/content-type/inputs.js +21 -0
  65. package/server/services/content-api/register-functions/index.js +22 -0
  66. package/server/services/content-api/register-functions/internals.js +13 -0
  67. package/server/services/content-api/register-functions/polymorphic.js +69 -0
  68. package/server/services/content-api/register-functions/scalars.js +14 -0
  69. package/server/services/content-api/register-functions/single-type.js +72 -0
  70. package/server/services/content-api/wrap-resolvers.js +144 -0
  71. package/server/services/extension/extension.js +95 -0
  72. package/server/services/extension/index.js +5 -0
  73. package/server/services/extension/shadow-crud-manager.js +159 -0
  74. package/server/services/format/index.js +7 -0
  75. package/server/services/format/return-types.js +27 -0
  76. package/server/services/index.js +21 -0
  77. package/server/services/internals/args/index.js +11 -0
  78. package/server/services/internals/args/pagination.js +19 -0
  79. package/server/services/internals/args/publication-state.js +12 -0
  80. package/server/services/internals/args/sort.js +10 -0
  81. package/server/services/internals/helpers/get-enabled-scalars.js +15 -0
  82. package/server/services/internals/helpers/index.js +7 -0
  83. package/server/services/internals/index.js +13 -0
  84. package/server/services/internals/scalars/index.js +18 -0
  85. package/server/services/internals/scalars/time.js +36 -0
  86. package/server/services/internals/types/error.js +34 -0
  87. package/server/services/internals/types/filters.js +39 -0
  88. package/server/services/internals/types/index.js +29 -0
  89. package/server/services/internals/types/pagination.js +24 -0
  90. package/server/services/internals/types/publication-state.js +24 -0
  91. package/server/services/internals/types/response-collection-meta.js +38 -0
  92. package/server/services/type-registry.js +104 -0
  93. package/server/services/utils/attributes.js +84 -0
  94. package/server/services/utils/index.js +11 -0
  95. package/server/services/utils/mappers/entity-to-response-entity.js +12 -0
  96. package/server/services/utils/mappers/graphql-filters-to-strapi-query.js +109 -0
  97. package/server/services/utils/mappers/graphql-scalar-to-operators.js +17 -0
  98. package/server/services/utils/mappers/index.js +13 -0
  99. package/server/services/utils/mappers/strapi-scalar-to-graphql-scalar.js +25 -0
  100. package/server/services/utils/naming.js +287 -0
  101. package/strapi-admin.js +3 -0
  102. package/strapi-server.js +7 -9
  103. package/admin/src/assets/images/logo.svg +0 -38
  104. package/config/routes.json +0 -3
  105. package/config/schema.graphql +0 -1
  106. package/config/settings.json +0 -12
  107. package/controllers/GraphQL.js +0 -9
  108. package/hooks/graphql/defaults.json +0 -5
  109. package/hooks/graphql/index.js +0 -174
  110. package/hooks/graphql/load-config.js +0 -42
  111. package/services/build-aggregation.js +0 -565
  112. package/services/data-loaders.js +0 -55
  113. package/services/naming.js +0 -15
  114. package/services/resolvers-builder.js +0 -204
  115. package/services/schema-definitions.js +0 -131
  116. package/services/schema-generator.js +0 -178
  117. package/services/shadow-crud.js +0 -612
  118. package/services/type-builder.js +0 -311
  119. package/services/utils.js +0 -200
  120. package/types/dynamiczoneScalar.js +0 -40
  121. package/types/publication-state.js +0 -16
  122. package/types/time.js +0 -26
@@ -0,0 +1,287 @@
1
+ 'use strict';
2
+
3
+ const { camelCase, upperFirst, lowerFirst, pipe, get } = require('lodash/fp');
4
+ const { singular } = require('pluralize');
5
+ const { ApplicationError } = require('@strapi/utils').errors;
6
+
7
+ module.exports = ({ strapi }) => {
8
+ /**
9
+ * Build a type name for a enum based on a content type & an attribute name
10
+ * @param {object} contentType
11
+ * @param {string} attributeName
12
+ * @return {string}
13
+ */
14
+ const getEnumName = (contentType, attributeName) => {
15
+ const { attributes } = contentType;
16
+ const { enumName } = attributes[attributeName];
17
+ const { modelType } = contentType;
18
+
19
+ const typeName =
20
+ modelType === 'component' ? getComponentName(contentType) : getTypeName(contentType);
21
+
22
+ const defaultEnumName = `ENUM_${typeName.toUpperCase()}_${attributeName.toUpperCase()}`;
23
+
24
+ return enumName || defaultEnumName;
25
+ };
26
+
27
+ /**
28
+ * Build the base type name for a given content type
29
+ * @param {object} contentType
30
+ * @param {object} options
31
+ * @param {'singular' | 'plural'} options.plurality
32
+ * @return {string}
33
+ */
34
+ const getTypeName = (contentType, { plurality = 'singular' } = {}) => {
35
+ const plugin = get('plugin', contentType);
36
+ const modelName = get('modelName', contentType);
37
+ const name =
38
+ plurality === 'singular'
39
+ ? get('info.singularName', contentType)
40
+ : get('info.pluralName', contentType);
41
+
42
+ const transformedPlugin = upperFirst(camelCase(plugin));
43
+ const transformedModelName = upperFirst(camelCase(name || singular(modelName)));
44
+
45
+ return `${transformedPlugin}${transformedModelName}`;
46
+ };
47
+
48
+ /**
49
+ * Build the entity's type name for a given content type
50
+ * @param {object} contentType
51
+ * @return {string}
52
+ */
53
+ const getEntityName = contentType => {
54
+ return `${getTypeName(contentType)}Entity`;
55
+ };
56
+
57
+ /**
58
+ * Build the entity meta type name for a given content type
59
+ * @param {object} contentType
60
+ * @return {string}
61
+ */
62
+ const getEntityMetaName = contentType => {
63
+ return `${getEntityName(contentType)}Meta`;
64
+ };
65
+
66
+ /**
67
+ * Build the entity response's type name for a given content type
68
+ * @param {object} contentType
69
+ * @return {string}
70
+ */
71
+ const getEntityResponseName = contentType => {
72
+ return `${getEntityName(contentType)}Response`;
73
+ };
74
+
75
+ /**
76
+ * Build the entity response collection's type name for a given content type
77
+ * @param {object} contentType
78
+ * @return {string}
79
+ */
80
+ const getEntityResponseCollectionName = contentType => {
81
+ return `${getEntityName(contentType)}ResponseCollection`;
82
+ };
83
+
84
+ /**
85
+ * Build the relation response collection's type name for a given content type
86
+ * @param {object} contentType
87
+ * @return {string}
88
+ */
89
+ const getRelationResponseCollectionName = contentType => {
90
+ return `${getTypeName(contentType)}RelationResponseCollection`;
91
+ };
92
+
93
+ /**
94
+ * Build a component type name based on its definition
95
+ * @param {object} contentType
96
+ * @return {string}
97
+ */
98
+ const getComponentName = contentType => {
99
+ return contentType.globalId;
100
+ };
101
+
102
+ /**
103
+ * Build a component type name based on a content type's attribute
104
+ * @param {object} attribute
105
+ * @return {string}
106
+ */
107
+ const getComponentNameFromAttribute = attribute => {
108
+ return strapi.components[attribute.component].globalId;
109
+ };
110
+
111
+ /**
112
+ * Build a dynamic zone type name based on a content type and an attribute name
113
+ * @param {object} contentType
114
+ * @param {string} attributeName
115
+ * @return {string}
116
+ */
117
+ const getDynamicZoneName = (contentType, attributeName) => {
118
+ const typeName = getTypeName(contentType);
119
+ const dzName = upperFirst(camelCase(attributeName));
120
+ const suffix = 'DynamicZone';
121
+
122
+ return `${typeName}${dzName}${suffix}`;
123
+ };
124
+
125
+ /**
126
+ * Build a dynamic zone input type name based on a content type and an attribute name
127
+ * @param {object} contentType
128
+ * @param {string} attributeName
129
+ * @return {string}
130
+ */
131
+ const getDynamicZoneInputName = (contentType, attributeName) => {
132
+ const dzName = getDynamicZoneName(contentType, attributeName);
133
+
134
+ return `${dzName}Input`;
135
+ };
136
+
137
+ /**
138
+ * Build a component input type name based on a content type and an attribute name
139
+ * @param {object} contentType
140
+ * @return {string}
141
+ */
142
+ const getComponentInputName = contentType => {
143
+ const componentName = getComponentName(contentType);
144
+
145
+ return `${componentName}Input`;
146
+ };
147
+
148
+ /**
149
+ * Build a content type input name based on a content type and an attribute name
150
+ * @param {object} contentType
151
+ * @return {string}
152
+ */
153
+ const getContentTypeInputName = contentType => {
154
+ const typeName = getTypeName(contentType);
155
+
156
+ return `${typeName}Input`;
157
+ };
158
+
159
+ /**
160
+ * Build the queries type name for a given content type
161
+ * @param {object} contentType
162
+ * @return {string}
163
+ */
164
+ const getEntityQueriesTypeName = contentType => {
165
+ return `${getEntityName(contentType)}Queries`;
166
+ };
167
+
168
+ /**
169
+ * Build the mutations type name for a given content type
170
+ * @param {object} contentType
171
+ * @return {string}
172
+ */
173
+ const getEntityMutationsTypeName = contentType => {
174
+ return `${getEntityName(contentType)}Mutations`;
175
+ };
176
+
177
+ /**
178
+ * Build the filters type name for a given content type
179
+ * @param {object} contentType
180
+ * @return {string}
181
+ */
182
+ const getFiltersInputTypeName = contentType => {
183
+ const isComponent = contentType.modelType === 'component';
184
+
185
+ const baseName = isComponent ? getComponentName(contentType) : getTypeName(contentType);
186
+
187
+ return `${baseName}FiltersInput`;
188
+ };
189
+
190
+ /**
191
+ * Build a filters type name for a given GraphQL scalar type
192
+ * @param {NexusGenScalars} scalarType
193
+ * @return {string}
194
+ */
195
+ const getScalarFilterInputTypeName = scalarType => {
196
+ return `${scalarType}FilterInput`;
197
+ };
198
+
199
+ /**
200
+ * Build a type name for a given content type & polymorphic attribute
201
+ * @param {object} contentType
202
+ * @param {string} attributeName
203
+ * @return {string}
204
+ */
205
+ const getMorphRelationTypeName = (contentType, attributeName) => {
206
+ const typeName = getTypeName(contentType);
207
+ const formattedAttr = upperFirst(camelCase(attributeName));
208
+
209
+ return `${typeName}${formattedAttr}Morph`;
210
+ };
211
+
212
+ /**
213
+ * Build a custom type name generator with different customization options
214
+ * @param {object} options
215
+ * @param {string} [options.prefix]
216
+ * @param {string} [options.suffix]
217
+ * @param {'upper' | 'lower'} [options.firstLetterCase]
218
+ * @param {'plural' | 'singular'} [options.plurality]
219
+ * @return {function(*=): string}
220
+ */
221
+ const buildCustomTypeNameGenerator = (options = {}) => {
222
+ // todo[v4]: use singularName & pluralName is available
223
+ const { prefix = '', suffix = '', plurality = 'singular', firstLetterCase = 'upper' } = options;
224
+
225
+ if (!['plural', 'singular'].includes(plurality)) {
226
+ throw new ApplicationError(
227
+ `"plurality" param must be either "plural" or "singular", but got: "${plurality}"`
228
+ );
229
+ }
230
+
231
+ const getCustomTypeName = pipe(
232
+ ct => getTypeName(ct, { plurality }),
233
+ firstLetterCase === 'upper' ? upperFirst : lowerFirst
234
+ );
235
+
236
+ return contentType => `${prefix}${getCustomTypeName(contentType)}${suffix}`;
237
+ };
238
+
239
+ const getFindQueryName = buildCustomTypeNameGenerator({
240
+ plurality: 'plural',
241
+ firstLetterCase: 'lower',
242
+ });
243
+
244
+ const getFindOneQueryName = buildCustomTypeNameGenerator({ firstLetterCase: 'lower' });
245
+
246
+ const getCreateMutationTypeName = buildCustomTypeNameGenerator({
247
+ prefix: 'create',
248
+ firstLetterCase: 'upper',
249
+ });
250
+
251
+ const getUpdateMutationTypeName = buildCustomTypeNameGenerator({
252
+ prefix: 'update',
253
+ firstLetterCase: 'upper',
254
+ });
255
+
256
+ const getDeleteMutationTypeName = buildCustomTypeNameGenerator({
257
+ prefix: 'delete',
258
+ firstLetterCase: 'upper',
259
+ });
260
+
261
+ return {
262
+ getEnumName,
263
+ getTypeName,
264
+ getEntityName,
265
+ getEntityMetaName,
266
+ getEntityResponseName,
267
+ getEntityResponseCollectionName,
268
+ getRelationResponseCollectionName,
269
+ getComponentName,
270
+ getComponentNameFromAttribute,
271
+ getDynamicZoneName,
272
+ getDynamicZoneInputName,
273
+ getComponentInputName,
274
+ getContentTypeInputName,
275
+ getEntityQueriesTypeName,
276
+ getEntityMutationsTypeName,
277
+ getFiltersInputTypeName,
278
+ getScalarFilterInputTypeName,
279
+ getMorphRelationTypeName,
280
+ buildCustomTypeNameGenerator,
281
+ getFindQueryName,
282
+ getFindOneQueryName,
283
+ getCreateMutationTypeName,
284
+ getUpdateMutationTypeName,
285
+ getDeleteMutationTypeName,
286
+ };
287
+ };
@@ -0,0 +1,3 @@
1
+ 'use strict';
2
+
3
+ module.exports = require('./admin/src').default;
package/strapi-server.js CHANGED
@@ -1,15 +1,13 @@
1
1
  'use strict';
2
2
 
3
+ const bootstrap = require('./server/bootstrap');
4
+ const services = require('./server/services');
5
+ const config = require('./server/config');
6
+
3
7
  module.exports = (/* strapi, config */) => {
4
8
  return {
5
- bootstrap: () => {},
6
- destroy: () => {},
7
- config: {},
8
- routes: [],
9
- controllers: {},
10
- services: () => {},
11
- policies: {},
12
- middlewares: {},
13
- contentTypes: {},
9
+ config,
10
+ bootstrap,
11
+ services,
14
12
  };
15
13
  };
@@ -1,38 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <svg width="25px" height="28px" viewBox="0 0 25 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3
- <!-- Generator: Sketch 46.1 (44463) - http://www.bohemiancoding.com/sketch -->
4
- <title>GraphQL_Logo</title>
5
- <desc>Created with Sketch.</desc>
6
- <defs></defs>
7
- <g id="Pages" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
8
- <g id="List-plugins" transform="translate(-302.000000, -668.000000)" fill-rule="nonzero" fill="#E535AB">
9
- <g id="Container" transform="translate(263.000000, 83.000000)">
10
- <g id="Content">
11
- <g id="Forms" transform="translate(1.000000, 78.000000)">
12
- <g id="List" transform="translate(15.000000, 19.000000)">
13
- <g id="9" transform="translate(0.000000, 484.000000)">
14
- <g id="GraphQL_Logo" transform="translate(23.000000, 4.000000)">
15
- <rect id="Rectangle-path" transform="translate(7.525343, 11.130007) rotate(-149.999272) translate(-7.525343, -11.130007) " x="6.93249876" y="-0.309026904" width="1.1856882" height="22.8780681"></rect>
16
- <rect id="Rectangle-path" x="1.05714286" y="19.1571429" width="22.8785714" height="1.18571429"></rect>
17
- <rect id="Rectangle-path" transform="translate(7.528064, 22.613421) rotate(-149.999272) translate(-7.528064, -22.613421) " x="0.921066787" y="22.0205773" width="13.213995" height="1.1856882"></rect>
18
- <rect id="Rectangle-path" transform="translate(17.469093, 5.393493) rotate(-149.999272) translate(-17.469093, -5.393493) " x="10.8620954" y="4.80064876" width="13.213995" height="1.1856882"></rect>
19
- <rect id="Rectangle-path" transform="translate(7.531236, 5.388979) rotate(-120.000728) translate(-7.531236, -5.388979) " x="6.93839161" y="-1.21801893" width="1.1856882" height="13.213995"></rect>
20
- <rect id="Rectangle-path" transform="translate(17.477229, 11.130221) rotate(-120.000728) translate(-17.477229, -11.130221) " x="6.03819452" y="10.5373773" width="22.8780681" height="1.1856882"></rect>
21
- <rect id="Rectangle-path" x="1.96428571" y="7.39285714" width="1.18571429" height="13.2142857"></rect>
22
- <rect id="Rectangle-path" x="21.85" y="7.39285714" width="1.18571429" height="13.2142857"></rect>
23
- <rect id="Rectangle-path" transform="translate(17.469043, 22.606829) rotate(-120.000728) translate(-17.469043, -22.606829) " x="16.9511971" y="16.8605264" width="1.0356915" height="11.4926043"></rect>
24
- <path d="M24.6071429,20.9928571 C23.9214286,22.1857143 22.3928571,22.5928571 21.2,21.9071429 C20.0071429,21.2214286 19.6,19.6928571 20.2857143,18.5 C20.9714286,17.3071429 22.5,16.9 23.6928571,17.5857143 C24.8928571,18.2785714 25.3,19.8 24.6071429,20.9928571" id="Shape"></path>
25
- <path d="M4.70714286,9.5 C4.02142857,10.6928571 2.49285714,11.1 1.3,10.4142857 C0.107142857,9.72857143 -0.3,8.2 0.385714286,7.00714286 C1.07142857,5.81428571 2.6,5.40714286 3.79285714,6.09285714 C4.98571429,6.78571429 5.39285714,8.30714286 4.70714286,9.5" id="Shape"></path>
26
- <path d="M0.392857143,20.9928571 C-0.292857143,19.8 0.114285714,18.2785714 1.30714286,17.5857143 C2.5,16.9 4.02142857,17.3071429 4.71428571,18.5 C5.4,19.6928571 4.99285714,21.2142857 3.8,21.9071429 C2.6,22.5928571 1.07857143,22.1857143 0.392857143,20.9928571" id="Shape"></path>
27
- <path d="M20.2928571,9.5 C19.6071429,8.30714286 20.0142857,6.78571429 21.2071429,6.09285714 C22.4,5.40714286 23.9214286,5.81428571 24.6142857,7.00714286 C25.3,8.2 24.8928571,9.72142857 23.7,10.4142857 C22.5071429,11.1 20.9785714,10.6928571 20.2928571,9.5" id="Shape"></path>
28
- <path d="M12.5,27.9857143 C11.1214286,27.9857143 10.0071429,26.8714286 10.0071429,25.4928571 C10.0071429,24.1142857 11.1214286,23 12.5,23 C13.8785714,23 14.9928571,24.1142857 14.9928571,25.4928571 C14.9928571,26.8642857 13.8785714,27.9857143 12.5,27.9857143" id="Shape"></path>
29
- <path d="M12.5,5 C11.1214286,5 10.0071429,3.88571429 10.0071429,2.50714286 C10.0071429,1.12857143 11.1214286,0.0142857143 12.5,0.0142857143 C13.8785714,0.0142857143 14.9928571,1.12857143 14.9928571,2.50714286 C14.9928571,3.88571429 13.8785714,5 12.5,5" id="Shape"></path>
30
- </g>
31
- </g>
32
- </g>
33
- </g>
34
- </g>
35
- </g>
36
- </g>
37
- </g>
38
- </svg>
@@ -1,3 +0,0 @@
1
- {
2
- "routes": []
3
- }
@@ -1 +0,0 @@
1
- module.exports = {};
@@ -1,12 +0,0 @@
1
- {
2
- "endpoint": "/graphql",
3
- "shadowCRUD": true,
4
- "playgroundAlways": false,
5
- "depthLimit": 7,
6
- "amountLimit": 100,
7
- "shareEnabled": false,
8
- "federation": false,
9
- "apolloServer": {
10
- "tracing": false
11
- }
12
- }
@@ -1,9 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * GraphQL.js controller
5
- *
6
- * @description: A set of functions called "actions" of the `GraphQL` plugin.
7
- */
8
-
9
- module.exports = {};
@@ -1,5 +0,0 @@
1
- {
2
- "graphql": {
3
- "enabled": true
4
- }
5
- }
@@ -1,174 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * Module dependencies
5
- */
6
-
7
- // Public node modules.
8
- const _ = require('lodash');
9
- const { ApolloServer } = require('apollo-server-koa');
10
- const depthLimit = require('graphql-depth-limit');
11
- const { graphqlUploadKoa } = require('graphql-upload');
12
- const loadConfigs = require('./load-config');
13
-
14
- const attachMetadataToResolvers = (schema, { api, plugin }) => {
15
- const { resolver = {} } = schema;
16
- if (_.isEmpty(resolver)) return schema;
17
-
18
- Object.keys(resolver).forEach(type => {
19
- if (!_.isPlainObject(resolver[type])) return;
20
-
21
- Object.keys(resolver[type]).forEach(resolverName => {
22
- if (!_.isPlainObject(resolver[type][resolverName])) return;
23
-
24
- resolver[type][resolverName]['_metadatas'] = {
25
- api,
26
- plugin,
27
- };
28
- });
29
- });
30
-
31
- return schema;
32
- };
33
-
34
- module.exports = strapi => {
35
- const { appPath, installedPlugins } = strapi.config;
36
-
37
- return {
38
- async beforeInitialize() {
39
- // Try to inject this hook just after the others hooks to skip the router processing.
40
- if (!strapi.config.get('hook.load.after')) {
41
- _.set(strapi.config.hook.load, 'after', []);
42
- }
43
-
44
- strapi.config.hook.load.after.push('graphql');
45
- // Load core utils.
46
-
47
- const { api, plugins, extensions } = await loadConfigs({
48
- appPath,
49
- installedPlugins,
50
- });
51
- _.merge(strapi, { api, plugins });
52
-
53
- // Create a merge of all the GraphQL configuration.
54
- const apisSchemas = Object.keys(strapi.api || {}).map(key => {
55
- const schema = _.get(strapi.api[key], 'config.schema.graphql', {});
56
- return attachMetadataToResolvers(schema, { api: key });
57
- });
58
-
59
- const pluginsSchemas = Object.keys(strapi.plugins || {}).map(key => {
60
- const schema = _.get(strapi.plugins[key], 'config.schema.graphql', {});
61
- return attachMetadataToResolvers(schema, { plugin: key });
62
- });
63
-
64
- const extensionsSchemas = Object.keys(extensions || {}).map(key => {
65
- const schema = _.get(extensions[key], 'config.schema.graphql', {});
66
- return attachMetadataToResolvers(schema, { plugin: key });
67
- });
68
-
69
- const baseSchema = mergeSchemas([...pluginsSchemas, ...extensionsSchemas, ...apisSchemas]);
70
-
71
- // save the final schema in the plugin's config
72
- _.set(strapi.plugins.graphql, 'config._schema.graphql', baseSchema);
73
- },
74
-
75
- initialize() {
76
- const schema = strapi.plugins.graphql.services['schema-generator'].generateSchema();
77
-
78
- if (_.isEmpty(schema)) {
79
- strapi.log.warn('The GraphQL schema has not been generated because it is empty');
80
-
81
- return;
82
- }
83
-
84
- const config = _.get(strapi.plugins.graphql, 'config', {});
85
-
86
- // TODO: Remove these deprecated options in favor of `apolloServer` in the next major version
87
- const deprecatedApolloServerConfig = {
88
- tracing: _.get(config, 'tracing', false),
89
- introspection: _.get(config, 'introspection', true),
90
- engine: _.get(config, 'engine', false),
91
- };
92
-
93
- if (['tracing', 'introspection', 'engine'].some(key => _.has(config, key))) {
94
- strapi.log.warn(
95
- 'The `tracing`, `introspection` and `engine` options are deprecated in favor of the `apolloServer` object and they will be removed in the next major version.'
96
- );
97
- }
98
-
99
- const apolloServerConfig = _.get(config, 'apolloServer', {});
100
-
101
- const serverParams = {
102
- schema,
103
- uploads: false,
104
- context: ({ ctx }) => {
105
- // Initiliase loaders for this request.
106
- // TODO: set loaders in the context not globally
107
-
108
- strapi.plugins.graphql.services['data-loaders'].initializeLoader();
109
-
110
- return {
111
- context: ctx,
112
- };
113
- },
114
- formatError: err => {
115
- const formatError = _.get(config, 'formatError', null);
116
-
117
- return typeof formatError === 'function' ? formatError(err) : err;
118
- },
119
- validationRules: [depthLimit(config.depthLimit)],
120
- playground: false,
121
- cors: false,
122
- bodyParserConfig: true,
123
- // TODO: Remove these deprecated options in favor of `apolloServerConfig` in the next major version
124
- ...deprecatedApolloServerConfig,
125
- ...apolloServerConfig,
126
- };
127
-
128
- // Disable GraphQL Playground in production environment.
129
- if (strapi.config.environment !== 'production' || config.playgroundAlways) {
130
- serverParams.playground = {
131
- endpoint: `${strapi.config.server.url}${config.endpoint}`,
132
- shareEnabled: config.shareEnabled,
133
- };
134
- }
135
-
136
- const server = new ApolloServer(serverParams);
137
-
138
- const uploadMiddleware = graphqlUploadKoa();
139
- strapi.app.use((ctx, next) => {
140
- if (ctx.path === config.endpoint) {
141
- return uploadMiddleware(ctx, next);
142
- }
143
-
144
- return next();
145
- });
146
- server.applyMiddleware({
147
- app: strapi.app,
148
- path: config.endpoint,
149
- });
150
-
151
- strapi.plugins.graphql.destroy = async () => {
152
- await server.stop();
153
- };
154
- },
155
- };
156
- };
157
-
158
- /**
159
- * Merges a list of schemas
160
- * @param {Array<Object>} schemas - The list of schemas to merge
161
- */
162
- const mergeSchemas = schemas => {
163
- return schemas.reduce((acc, el) => {
164
- const { definition, query, mutation, type, resolver } = el;
165
-
166
- return _.merge(acc, {
167
- definition: `${acc.definition || ''} ${definition || ''}`,
168
- query: `${acc.query || ''} ${query || ''}`,
169
- mutation: `${acc.mutation || ''} ${mutation || ''}`,
170
- type,
171
- resolver,
172
- });
173
- }, {});
174
- };
@@ -1,42 +0,0 @@
1
- 'use strict';
2
-
3
- // eslint-disable-next-line node/no-extraneous-require
4
- const loadUtils = require('@strapi/strapi/lib/load');
5
- const _ = require('lodash');
6
-
7
- const loadApisGraphqlConfig = appPath =>
8
- loadUtils.loadFiles(appPath, 'api/**/config/*.graphql?(.js)');
9
-
10
- const loadPluginsGraphqlConfig = async installedPlugins => {
11
- const root = {};
12
-
13
- for (let pluginName of installedPlugins) {
14
- const pluginDir = loadUtils.findPackagePath(`@strapi/plugin-${pluginName}`);
15
-
16
- const result = await loadUtils.loadFiles(pluginDir, 'config/*.graphql?(.js)');
17
-
18
- _.set(root, ['plugins', pluginName], result);
19
- }
20
-
21
- return root;
22
- };
23
-
24
- const loadLocalPluginsGraphqlConfig = async appPath =>
25
- loadUtils.loadFiles(appPath, 'plugins/**/config/*.graphql?(.js)');
26
-
27
- const loadExtensions = async appPath =>
28
- loadUtils.loadFiles(appPath, 'extensions/**/config/*.graphql?(.js)');
29
-
30
- /**
31
- * Loads the graphql config files
32
- */
33
- module.exports = async ({ appPath, installedPlugins }) => {
34
- const [apis, plugins, localPlugins, extensions] = await Promise.all([
35
- loadApisGraphqlConfig(appPath),
36
- loadPluginsGraphqlConfig(installedPlugins),
37
- loadLocalPluginsGraphqlConfig(appPath),
38
- loadExtensions(appPath),
39
- ]);
40
-
41
- return _.merge({}, apis, plugins, extensions, localPlugins);
42
- };