@strapi/plugin-graphql 4.0.0-next.2 → 4.0.0-next.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.
- package/admin/src/translations/zh-Hans.json +4 -0
- package/package.json +17 -15
- package/server/bootstrap.js +124 -0
- package/server/services/builders/dynamic-zones.js +96 -0
- package/server/services/builders/entity-meta.js +7 -0
- package/server/services/builders/entity.js +43 -0
- package/server/services/builders/enums.js +24 -0
- package/server/services/builders/filters/content-type.js +84 -0
- package/server/services/builders/filters/index.js +7 -0
- package/server/services/builders/filters/operators/and.js +15 -0
- package/server/services/builders/filters/operators/between.js +15 -0
- package/server/services/builders/filters/operators/contains.js +13 -0
- package/server/services/builders/filters/operators/containsi.js +13 -0
- package/server/services/builders/filters/operators/ends-with.js +13 -0
- package/server/services/builders/filters/operators/eq.js +19 -0
- package/server/services/builders/filters/operators/gt.js +13 -0
- package/server/services/builders/filters/operators/gte.js +13 -0
- package/server/services/builders/filters/operators/in.js +15 -0
- package/server/services/builders/filters/operators/index.js +38 -0
- package/server/services/builders/filters/operators/lt.js +13 -0
- package/server/services/builders/filters/operators/lte.js +13 -0
- package/server/services/builders/filters/operators/ne.js +13 -0
- package/server/services/builders/filters/operators/not-contains.js +13 -0
- package/server/services/builders/filters/operators/not-containsi.js +13 -0
- package/server/services/builders/filters/operators/not-in.js +15 -0
- package/server/services/builders/filters/operators/not-null.js +13 -0
- package/server/services/builders/filters/operators/not.js +19 -0
- package/server/services/builders/filters/operators/null.js +13 -0
- package/server/services/builders/filters/operators/or.js +15 -0
- package/server/services/builders/filters/operators/starts-with.js +13 -0
- package/server/services/builders/generic-morph.js +41 -0
- package/server/services/builders/index.js +92 -0
- package/server/services/builders/input.js +118 -0
- package/server/services/builders/mutations/collection-type.js +170 -0
- package/server/services/builders/mutations/index.js +9 -0
- package/server/services/builders/mutations/single-type.js +135 -0
- package/server/services/builders/queries/collection-type.js +120 -0
- package/server/services/builders/queries/index.js +9 -0
- package/server/services/builders/queries/single-type.js +70 -0
- package/server/services/builders/relation-response-collection.js +35 -0
- package/server/services/builders/resolvers/association.js +64 -0
- package/server/services/builders/resolvers/component.js +14 -0
- package/server/services/builders/resolvers/dynamic-zone.js +9 -0
- package/server/services/builders/resolvers/index.js +18 -0
- package/server/services/builders/resolvers/mutation.js +33 -0
- package/server/services/builders/resolvers/query.js +19 -0
- package/server/services/builders/response-collection.js +43 -0
- package/server/services/builders/response.js +32 -0
- package/server/services/builders/type.js +370 -0
- package/server/services/builders/utils.js +131 -0
- package/server/services/constants.js +147 -0
- package/server/services/content-api/index.js +168 -0
- package/server/services/content-api/policy.js +59 -0
- package/server/services/content-api/register-functions/collection-type.js +72 -0
- package/server/services/content-api/register-functions/component.js +15 -0
- package/server/services/content-api/register-functions/content-type/dynamic-zones.js +36 -0
- package/server/services/content-api/register-functions/content-type/enums.js +33 -0
- package/server/services/content-api/register-functions/content-type/filters.js +15 -0
- package/server/services/content-api/register-functions/content-type/index.js +13 -0
- package/server/services/content-api/register-functions/content-type/inputs.js +21 -0
- package/server/services/content-api/register-functions/index.js +22 -0
- package/server/services/content-api/register-functions/internals.js +13 -0
- package/server/services/content-api/register-functions/polymorphic.js +69 -0
- package/server/services/content-api/register-functions/scalars.js +14 -0
- package/server/services/content-api/register-functions/single-type.js +72 -0
- package/server/services/content-api/wrap-resolvers.js +146 -0
- package/server/services/extension/extension.js +95 -0
- package/server/services/extension/index.js +5 -0
- package/server/services/extension/shadow-crud-manager.js +159 -0
- package/server/services/format/index.js +7 -0
- package/server/services/format/return-types.js +27 -0
- package/server/services/index.js +21 -0
- package/server/services/internals/args/index.js +11 -0
- package/server/services/internals/args/pagination.js +19 -0
- package/server/services/internals/args/publication-state.js +12 -0
- package/server/services/internals/args/sort.js +10 -0
- package/server/services/internals/helpers/get-enabled-scalars.js +15 -0
- package/server/services/internals/helpers/index.js +7 -0
- package/server/services/internals/index.js +13 -0
- package/server/services/internals/scalars/index.js +18 -0
- package/server/services/internals/scalars/time.js +35 -0
- package/server/services/internals/types/error.js +33 -0
- package/server/services/internals/types/filters.js +39 -0
- package/server/services/internals/types/index.js +29 -0
- package/server/services/internals/types/pagination.js +24 -0
- package/server/services/internals/types/publication-state.js +24 -0
- package/server/services/internals/types/response-collection-meta.js +38 -0
- package/server/services/type-registry.js +103 -0
- package/server/services/utils/attributes.js +84 -0
- package/server/services/utils/index.js +11 -0
- package/server/services/utils/mappers/entity-to-response-entity.js +12 -0
- package/server/services/utils/mappers/graphql-filters-to-strapi-query.js +107 -0
- package/server/services/utils/mappers/graphql-scalar-to-operators.js +17 -0
- package/server/services/utils/mappers/index.js +13 -0
- package/server/services/utils/mappers/strapi-scalar-to-graphql-scalar.js +24 -0
- package/server/services/utils/naming.js +282 -0
- package/strapi-admin.js +3 -0
- package/strapi-server.js +11 -0
- package/config/routes.json +0 -3
- package/config/schema.graphql +0 -1
- package/config/settings.json +0 -12
- package/controllers/GraphQL.js +0 -9
- package/hooks/graphql/defaults.json +0 -5
- package/hooks/graphql/index.js +0 -174
- package/hooks/graphql/load-config.js +0 -42
- package/services/build-aggregation.js +0 -565
- package/services/data-loaders.js +0 -55
- package/services/naming.js +0 -15
- package/services/resolvers-builder.js +0 -204
- package/services/schema-definitions.js +0 -131
- package/services/schema-generator.js +0 -178
- package/services/shadow-crud.js +0 -612
- package/services/type-builder.js +0 -311
- package/services/utils.js +0 -200
- package/types/dynamiczoneScalar.js +0 -40
- package/types/publication-state.js +0 -16
- package/types/time.js +0 -26
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { camelCase, upperFirst, lowerFirst, pipe, get } = require('lodash/fp');
|
|
4
|
+
const { singular } = require('pluralize');
|
|
5
|
+
|
|
6
|
+
module.exports = ({ strapi }) => {
|
|
7
|
+
/**
|
|
8
|
+
* Build a type name for a enum based on a content type & an attribute name
|
|
9
|
+
* @param {object} contentType
|
|
10
|
+
* @param {string} attributeName
|
|
11
|
+
* @return {string}
|
|
12
|
+
*/
|
|
13
|
+
const getEnumName = (contentType, attributeName) => {
|
|
14
|
+
const { attributes, modelName } = contentType;
|
|
15
|
+
const { enumName } = attributes[attributeName];
|
|
16
|
+
|
|
17
|
+
const defaultEnumName = `ENUM_${modelName.toUpperCase()}_${attributeName.toUpperCase()}`;
|
|
18
|
+
|
|
19
|
+
return enumName || defaultEnumName;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Build the base type name for a given content type
|
|
24
|
+
* @param {object} contentType
|
|
25
|
+
* @param {object} options
|
|
26
|
+
* @param {'singular' | 'plural'} options.plurality
|
|
27
|
+
* @return {string}
|
|
28
|
+
*/
|
|
29
|
+
const getTypeName = (contentType, { plurality = 'singular' } = {}) => {
|
|
30
|
+
const plugin = get('plugin', contentType);
|
|
31
|
+
const modelName = get('modelName', contentType);
|
|
32
|
+
const name =
|
|
33
|
+
plurality === 'singular'
|
|
34
|
+
? get('info.singularName', contentType)
|
|
35
|
+
: get('info.pluralName', contentType);
|
|
36
|
+
|
|
37
|
+
const transformedPlugin = upperFirst(camelCase(plugin));
|
|
38
|
+
const transformedModelName = upperFirst(camelCase(name || singular(modelName)));
|
|
39
|
+
|
|
40
|
+
return `${transformedPlugin}${transformedModelName}`;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Build the entity's type name for a given content type
|
|
45
|
+
* @param {object} contentType
|
|
46
|
+
* @return {string}
|
|
47
|
+
*/
|
|
48
|
+
const getEntityName = contentType => {
|
|
49
|
+
return `${getTypeName(contentType)}Entity`;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Build the entity meta type name for a given content type
|
|
54
|
+
* @param {object} contentType
|
|
55
|
+
* @return {string}
|
|
56
|
+
*/
|
|
57
|
+
const getEntityMetaName = contentType => {
|
|
58
|
+
return `${getEntityName(contentType)}Meta`;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Build the entity response's type name for a given content type
|
|
63
|
+
* @param {object} contentType
|
|
64
|
+
* @return {string}
|
|
65
|
+
*/
|
|
66
|
+
const getEntityResponseName = contentType => {
|
|
67
|
+
return `${getEntityName(contentType)}Response`;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Build the entity response collection's type name for a given content type
|
|
72
|
+
* @param {object} contentType
|
|
73
|
+
* @return {string}
|
|
74
|
+
*/
|
|
75
|
+
const getEntityResponseCollectionName = contentType => {
|
|
76
|
+
return `${getEntityName(contentType)}ResponseCollection`;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Build the relation response collection's type name for a given content type
|
|
81
|
+
* @param {object} contentType
|
|
82
|
+
* @return {string}
|
|
83
|
+
*/
|
|
84
|
+
const getRelationResponseCollectionName = contentType => {
|
|
85
|
+
return `${getTypeName(contentType)}RelationResponseCollection`;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Build a component type name based on its definition
|
|
90
|
+
* @param {object} contentType
|
|
91
|
+
* @return {string}
|
|
92
|
+
*/
|
|
93
|
+
const getComponentName = contentType => {
|
|
94
|
+
return contentType.globalId;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Build a component type name based on a content type's attribute
|
|
99
|
+
* @param {object} attribute
|
|
100
|
+
* @return {string}
|
|
101
|
+
*/
|
|
102
|
+
const getComponentNameFromAttribute = attribute => {
|
|
103
|
+
return strapi.components[attribute.component].globalId;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Build a dynamic zone type name based on a content type and an attribute name
|
|
108
|
+
* @param {object} contentType
|
|
109
|
+
* @param {string} attributeName
|
|
110
|
+
* @return {string}
|
|
111
|
+
*/
|
|
112
|
+
const getDynamicZoneName = (contentType, attributeName) => {
|
|
113
|
+
const typeName = getTypeName(contentType);
|
|
114
|
+
const dzName = upperFirst(camelCase(attributeName));
|
|
115
|
+
const suffix = 'DynamicZone';
|
|
116
|
+
|
|
117
|
+
return `${typeName}${dzName}${suffix}`;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Build a dynamic zone input type name based on a content type and an attribute name
|
|
122
|
+
* @param {object} contentType
|
|
123
|
+
* @param {string} attributeName
|
|
124
|
+
* @return {string}
|
|
125
|
+
*/
|
|
126
|
+
const getDynamicZoneInputName = (contentType, attributeName) => {
|
|
127
|
+
const dzName = getDynamicZoneName(contentType, attributeName);
|
|
128
|
+
|
|
129
|
+
return `${dzName}Input`;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Build a component input type name based on a content type and an attribute name
|
|
134
|
+
* @param {object} contentType
|
|
135
|
+
* @return {string}
|
|
136
|
+
*/
|
|
137
|
+
const getComponentInputName = contentType => {
|
|
138
|
+
const componentName = getComponentName(contentType);
|
|
139
|
+
|
|
140
|
+
return `${componentName}Input`;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Build a content type input name based on a content type and an attribute name
|
|
145
|
+
* @param {object} contentType
|
|
146
|
+
* @return {string}
|
|
147
|
+
*/
|
|
148
|
+
const getContentTypeInputName = contentType => {
|
|
149
|
+
const typeName = getTypeName(contentType);
|
|
150
|
+
|
|
151
|
+
return `${typeName}Input`;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Build the queries type name for a given content type
|
|
156
|
+
* @param {object} contentType
|
|
157
|
+
* @return {string}
|
|
158
|
+
*/
|
|
159
|
+
const getEntityQueriesTypeName = contentType => {
|
|
160
|
+
return `${getEntityName(contentType)}Queries`;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Build the mutations type name for a given content type
|
|
165
|
+
* @param {object} contentType
|
|
166
|
+
* @return {string}
|
|
167
|
+
*/
|
|
168
|
+
const getEntityMutationsTypeName = contentType => {
|
|
169
|
+
return `${getEntityName(contentType)}Mutations`;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Build the filters type name for a given content type
|
|
174
|
+
* @param {object} contentType
|
|
175
|
+
* @return {string}
|
|
176
|
+
*/
|
|
177
|
+
const getFiltersInputTypeName = contentType => {
|
|
178
|
+
const isComponent = contentType.modelType === 'component';
|
|
179
|
+
|
|
180
|
+
const baseName = isComponent ? getComponentName(contentType) : getTypeName(contentType);
|
|
181
|
+
|
|
182
|
+
return `${baseName}FiltersInput`;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Build a filters type name for a given GraphQL scalar type
|
|
187
|
+
* @param {NexusGenScalars} scalarType
|
|
188
|
+
* @return {string}
|
|
189
|
+
*/
|
|
190
|
+
const getScalarFilterInputTypeName = scalarType => {
|
|
191
|
+
return `${scalarType}FilterInput`;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Build a type name for a given content type & polymorphic attribute
|
|
196
|
+
* @param {object} contentType
|
|
197
|
+
* @param {string} attributeName
|
|
198
|
+
* @return {string}
|
|
199
|
+
*/
|
|
200
|
+
const getMorphRelationTypeName = (contentType, attributeName) => {
|
|
201
|
+
const typeName = getTypeName(contentType);
|
|
202
|
+
const formattedAttr = upperFirst(camelCase(attributeName));
|
|
203
|
+
|
|
204
|
+
return `${typeName}${formattedAttr}Morph`;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Build a custom type name generator with different customization options
|
|
209
|
+
* @param {object} options
|
|
210
|
+
* @param {string} [options.prefix]
|
|
211
|
+
* @param {string} [options.suffix]
|
|
212
|
+
* @param {'upper' | 'lower'} [options.firstLetterCase]
|
|
213
|
+
* @param {'plural' | 'singular'} [options.plurality]
|
|
214
|
+
* @return {function(*=): string}
|
|
215
|
+
*/
|
|
216
|
+
const buildCustomTypeNameGenerator = (options = {}) => {
|
|
217
|
+
// todo[v4]: use singularName & pluralName is available
|
|
218
|
+
const { prefix = '', suffix = '', plurality = 'singular', firstLetterCase = 'upper' } = options;
|
|
219
|
+
|
|
220
|
+
if (!['plural', 'singular'].includes(plurality)) {
|
|
221
|
+
throw new Error(
|
|
222
|
+
`"plurality" param must be either "plural" or "singular", but got: "${plurality}"`
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const getCustomTypeName = pipe(
|
|
227
|
+
ct => getTypeName(ct, { plurality }),
|
|
228
|
+
firstLetterCase === 'upper' ? upperFirst : lowerFirst
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
return contentType => `${prefix}${getCustomTypeName(contentType)}${suffix}`;
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
const getFindQueryName = buildCustomTypeNameGenerator({
|
|
235
|
+
plurality: 'plural',
|
|
236
|
+
firstLetterCase: 'lower',
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
const getFindOneQueryName = buildCustomTypeNameGenerator({ firstLetterCase: 'lower' });
|
|
240
|
+
|
|
241
|
+
const getCreateMutationTypeName = buildCustomTypeNameGenerator({
|
|
242
|
+
prefix: 'create',
|
|
243
|
+
firstLetterCase: 'upper',
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
const getUpdateMutationTypeName = buildCustomTypeNameGenerator({
|
|
247
|
+
prefix: 'update',
|
|
248
|
+
firstLetterCase: 'upper',
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
const getDeleteMutationTypeName = buildCustomTypeNameGenerator({
|
|
252
|
+
prefix: 'delete',
|
|
253
|
+
firstLetterCase: 'upper',
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
return {
|
|
257
|
+
getEnumName,
|
|
258
|
+
getTypeName,
|
|
259
|
+
getEntityName,
|
|
260
|
+
getEntityMetaName,
|
|
261
|
+
getEntityResponseName,
|
|
262
|
+
getEntityResponseCollectionName,
|
|
263
|
+
getRelationResponseCollectionName,
|
|
264
|
+
getComponentName,
|
|
265
|
+
getComponentNameFromAttribute,
|
|
266
|
+
getDynamicZoneName,
|
|
267
|
+
getDynamicZoneInputName,
|
|
268
|
+
getComponentInputName,
|
|
269
|
+
getContentTypeInputName,
|
|
270
|
+
getEntityQueriesTypeName,
|
|
271
|
+
getEntityMutationsTypeName,
|
|
272
|
+
getFiltersInputTypeName,
|
|
273
|
+
getScalarFilterInputTypeName,
|
|
274
|
+
getMorphRelationTypeName,
|
|
275
|
+
buildCustomTypeNameGenerator,
|
|
276
|
+
getFindQueryName,
|
|
277
|
+
getFindOneQueryName,
|
|
278
|
+
getCreateMutationTypeName,
|
|
279
|
+
getUpdateMutationTypeName,
|
|
280
|
+
getDeleteMutationTypeName,
|
|
281
|
+
};
|
|
282
|
+
};
|
package/strapi-admin.js
ADDED
package/strapi-server.js
ADDED
package/config/routes.json
DELETED
package/config/schema.graphql
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
module.exports = {};
|
package/config/settings.json
DELETED
package/controllers/GraphQL.js
DELETED
package/hooks/graphql/index.js
DELETED
|
@@ -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
|
-
};
|