@strapi/plugin-graphql 4.0.0-next.8 → 4.0.2

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 +43 -35
  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 +149 -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 +39 -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
@@ -1,204 +0,0 @@
1
- /**
2
- * Build queries and mutation resolvers
3
- */
4
-
5
- 'use strict';
6
-
7
- const _ = require('lodash');
8
- const compose = require('koa-compose');
9
-
10
- const { policy: policyUtils } = require('@strapi/utils');
11
- const {
12
- convertToParams,
13
- convertToQuery,
14
- amountLimiting,
15
- getAction,
16
- getActionDetails,
17
- isResolvablePath,
18
- } = require('./utils');
19
-
20
- const buildMutation = (mutationName, config) => {
21
- const { resolver, resolverOf, transformOutput = _.identity, isShadowCrud = false } = config;
22
-
23
- if (_.isFunction(resolver) && !isResolvablePath(resolverOf)) {
24
- throw new Error(
25
- `Cannot create mutation "${mutationName}". Missing "resolverOf" option with custom resolver.`
26
- );
27
- }
28
-
29
- const policiesMiddleware = compose(getPolicies(config));
30
-
31
- // custom resolvers
32
- if (_.isFunction(resolver)) {
33
- return async (root, options = {}, graphqlContext, info) => {
34
- const ctx = buildMutationContext({ options, graphqlContext, isShadowCrud });
35
-
36
- await policiesMiddleware(ctx);
37
- graphqlContext.context = ctx;
38
-
39
- return resolver(root, options, graphqlContext, info);
40
- };
41
- }
42
-
43
- const action = getAction(resolver);
44
-
45
- return async (root, options = {}, graphqlContext) => {
46
- const ctx = buildMutationContext({ options, graphqlContext, isShadowCrud });
47
-
48
- await policiesMiddleware(ctx);
49
-
50
- const values = await action(ctx);
51
- const result = ctx.body !== undefined ? ctx.body : values;
52
-
53
- if (_.isError(result)) {
54
- throw result;
55
- }
56
-
57
- return transformOutput(result);
58
- };
59
- };
60
-
61
- const buildMutationContext = ({ options, graphqlContext, isShadowCrud }) => {
62
- const { context } = graphqlContext;
63
-
64
- const ctx = cloneKoaContext(context);
65
-
66
- if (options.input && options.input.where) {
67
- ctx.params = convertToParams(options.input.where || {});
68
- } else {
69
- ctx.params = {};
70
- }
71
-
72
- if (options.input && options.input.data) {
73
- ctx.request.body = options.input.data || {};
74
- } else {
75
- ctx.request.body = options;
76
- }
77
-
78
- if (isShadowCrud) {
79
- ctx.query = convertToParams(_.omit(options, 'input'));
80
- }
81
-
82
- return ctx;
83
- };
84
-
85
- const buildQuery = (queryName, config) => {
86
- const { resolver } = config;
87
-
88
- try {
89
- validateResolverOption(config);
90
- } catch (error) {
91
- throw new Error(`Cannot create query "${queryName}": ${error.message}`);
92
- }
93
-
94
- const policiesMiddleware = compose(getPolicies(config));
95
-
96
- // custom resolvers
97
- if (_.isFunction(resolver)) {
98
- return async (root, options = {}, graphqlContext, info) => {
99
- const { ctx, opts } = buildQueryContext({ options, graphqlContext });
100
-
101
- await policiesMiddleware(ctx);
102
- graphqlContext.context = ctx;
103
-
104
- return resolver(root, opts, graphqlContext, info);
105
- };
106
- }
107
-
108
- const action = getAction(resolver);
109
-
110
- return async (root, options = {}, graphqlContext) => {
111
- const { ctx } = buildQueryContext({ options, graphqlContext });
112
-
113
- // duplicate context
114
- await policiesMiddleware(ctx);
115
-
116
- const values = await action(ctx);
117
- const result = ctx.body !== undefined ? ctx.body : values;
118
-
119
- if (_.isError(result)) {
120
- throw result;
121
- }
122
-
123
- return result;
124
- };
125
- };
126
-
127
- const validateResolverOption = config => {
128
- const { resolver, resolverOf, policies } = config;
129
-
130
- if (_.isFunction(resolver) && !isResolvablePath(resolverOf)) {
131
- throw new Error(`Missing "resolverOf" option with custom resolver.`);
132
- }
133
-
134
- if (!_.isUndefined(policies) && (!Array.isArray(policies) || !_.every(policies, _.isString))) {
135
- throw new Error('Policies option must be an array of string.');
136
- }
137
-
138
- return true;
139
- };
140
-
141
- const cloneKoaContext = ctx => {
142
- return Object.assign(ctx.app.createContext(_.clone(ctx.req), _.clone(ctx.res)), {
143
- state: {
144
- ...ctx.state,
145
- },
146
- });
147
- };
148
-
149
- const buildQueryContext = ({ options, graphqlContext }) => {
150
- const { context } = graphqlContext;
151
- const _options = _.cloneDeep(options);
152
-
153
- const ctx = cloneKoaContext(context);
154
-
155
- const opts = amountLimiting(_options);
156
-
157
- ctx.query = {
158
- ...convertToParams(_.omit(opts, 'where')),
159
- ...convertToQuery(opts.where),
160
- };
161
-
162
- ctx.params = convertToParams(opts);
163
-
164
- return { ctx, opts };
165
- };
166
-
167
- /**
168
- * Checks if a resolverPath (resolver or resovlerOf) might be resolved
169
- */
170
- const getPolicies = config => {
171
- const { resolver, policies = [], resolverOf } = config;
172
-
173
- const { api, plugin } = config['_metadatas'] || {};
174
-
175
- const policyFns = [];
176
-
177
- const { controller, action, plugin: pathPlugin } = isResolvablePath(resolverOf)
178
- ? getActionDetails(resolverOf)
179
- : getActionDetails(resolver);
180
-
181
- const globalPolicy = policyUtils.globalPolicy({
182
- controller,
183
- action,
184
- plugin: pathPlugin,
185
- });
186
-
187
- policyFns.push(globalPolicy);
188
-
189
- if (strapi.plugins['users-permissions']) {
190
- policies.unshift('plugin::users-permissions.permissions');
191
- }
192
-
193
- policies.forEach(policy => {
194
- const policyFn = policyUtils.get(policy, plugin, api);
195
- policyFns.push(policyFn);
196
- });
197
-
198
- return policyFns;
199
- };
200
-
201
- module.exports = {
202
- buildQuery,
203
- buildMutation,
204
- };
@@ -1,131 +0,0 @@
1
- /**
2
- * Schema definition language tools
3
- */
4
-
5
- 'use strict';
6
-
7
- const _ = require('lodash');
8
-
9
- /**
10
- * Retrieves a type description from its configuration or its related model
11
- * @return String
12
- */
13
- const getTypeDescription = (type, model = {}) => {
14
- const str = _.get(type, '_description') || _.get(model, 'info.description');
15
-
16
- if (str) {
17
- return `"""\n${str}\n"""\n`;
18
- }
19
-
20
- return '';
21
- };
22
-
23
- /**
24
- * Receive an Object and return a string which is following the GraphQL specs.
25
- * @param {Object} fields
26
- * @param {Object} description
27
- * @param {Object} model the underlying strapi model of those fields
28
- * @param {string} type the type of object we are converting to SQL (query, mutation, or fields)
29
- */
30
- const toSDL = (fields, configurations = {}, model = {}, type = 'field') => {
31
- if (['query', 'mutation'].includes(type)) {
32
- return operationToSDL({ fields, configurations });
33
- }
34
-
35
- return fieldsToSDL({ fields, model, configurations });
36
- };
37
-
38
- /**
39
- * Generated a SDL for a type
40
- * @param {Object} options
41
- * @param {Object} options.fields fields to convert to SDL
42
- * @param {Object} options.configurations fields configurations (descriptions and deprecations)
43
- * @param {Object} options.model the underlying strapi model of those fields
44
- */
45
- const fieldsToSDL = ({ fields, configurations, model }) => {
46
- return Object.entries(fields)
47
- .map(([key, value]) => {
48
- const [attr] = key.split('(');
49
- const attributeName = _.trim(attr);
50
-
51
- const description = _.isString(configurations[attributeName])
52
- ? configurations[attributeName]
53
- : _.get(configurations, [attributeName, 'description']) ||
54
- _.get(model, ['attributes', attributeName, 'description']);
55
-
56
- const deprecated =
57
- _.get(configurations, [attributeName, 'deprecated']) ||
58
- _.get(model, ['attributes', attributeName, 'deprecated']);
59
-
60
- return applyMetadatas(`${key}: ${value}`, { description, deprecated });
61
- })
62
- .join('\n');
63
- };
64
-
65
- /**
66
- * Generated a SDL for a query or a mutation object
67
- * @param {Object} options
68
- * @param {Object} options.fields fields to convert to SDL
69
- * @param {Object} options.configurations fields configurations (descriptions and deprecations)
70
- */
71
- const operationToSDL = ({ fields, configurations }) => {
72
- return Object.entries(fields)
73
- .map(([key, value]) => {
74
- if (typeof value === 'string') {
75
- const [attr] = key.split('(');
76
- const attributeName = _.trim(attr);
77
-
78
- return applyMetadatas(`${key}: ${value}`, configurations[attributeName]);
79
- } else {
80
- const { args = {}, type } = value;
81
-
82
- const query = `${key}${argumentsToSDL(args)}: ${type}`;
83
- return applyMetadatas(query, configurations[key]);
84
- }
85
- })
86
- .join('\n');
87
- };
88
-
89
- /**
90
- * Converts an object of arguments into graphql SDL
91
- * @param {object} args arguments
92
- * @returns {string}
93
- */
94
- const argumentsToSDL = args => {
95
- if (_.isEmpty(args)) {
96
- return '';
97
- }
98
-
99
- const sdlArgs = Object.entries(args)
100
- .map(([key, value]) => `${key}: ${value}`)
101
- .join(', ');
102
-
103
- return `(${sdlArgs})`;
104
- };
105
-
106
- /**
107
- * Applies description and deprecated to a field definition
108
- * @param {string} definition field definition
109
- * @param {Object} metadatas field metadatas
110
- * @param {string} metadatas.description field description
111
- * @param {string} metadatas.deprecated field deprecation
112
- */
113
- const applyMetadatas = (definition, metadatas = {}) => {
114
- const { description, deprecated } = metadatas;
115
-
116
- let tmpDef = definition;
117
- if (description) {
118
- tmpDef = `"""\n${description}\n"""\n${tmpDef}`;
119
- }
120
-
121
- if (deprecated) {
122
- tmpDef = `${tmpDef} @deprecated(reason: "${deprecated}")`;
123
- }
124
-
125
- return tmpDef;
126
- };
127
-
128
- module.exports = {
129
- toSDL,
130
- getTypeDescription,
131
- };
@@ -1,178 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * GraphQL.js service
5
- *
6
- * @description: A set of functions similar to controller's actions to avoid code duplication.
7
- */
8
- const { filterSchema } = require('@graphql-tools/utils');
9
- const { buildFederatedSchema } = require('@apollo/federation');
10
- const { gql, makeExecutableSchema } = require('apollo-server-koa');
11
- const _ = require('lodash');
12
- const graphql = require('graphql');
13
- const PublicationState = require('../types/publication-state');
14
- const Types = require('./type-builder');
15
- const buildShadowCrud = require('./shadow-crud');
16
- const { createDefaultSchema, diffResolvers } = require('./utils');
17
- const { toSDL } = require('./schema-definitions');
18
- const { buildQuery, buildMutation } = require('./resolvers-builder');
19
-
20
- /**
21
- * Generate GraphQL schema.
22
- *
23
- * @return Schema
24
- */
25
-
26
- const generateSchema = () => {
27
- const isFederated = _.get(strapi.plugins.graphql.config, 'federation', false);
28
- const shadowCRUDEnabled = strapi.plugins.graphql.config.shadowCRUD !== false;
29
-
30
- const _schema = strapi.plugins.graphql.config._schema.graphql;
31
-
32
- const ctx = {
33
- schema: _schema,
34
- };
35
-
36
- // Generate type definition and query/mutation for models.
37
- const shadowCRUD = shadowCRUDEnabled ? buildShadowCrud(ctx) : createDefaultSchema();
38
-
39
- // Extract custom definition, query or resolver.
40
- const { definition, query, mutation, resolver = {} } = _schema;
41
-
42
- // Polymorphic.
43
- const polymorphicSchema = Types.addPolymorphicUnionType(definition + shadowCRUD.definition);
44
-
45
- const builtResolvers = _.merge({}, shadowCRUD.resolvers, polymorphicSchema.resolvers);
46
-
47
- const extraResolvers = diffResolvers(_schema.resolver, builtResolvers);
48
-
49
- const resolvers = _.merge({}, builtResolvers, buildResolvers(extraResolvers));
50
-
51
- // Return empty schema when there is no model.
52
- if (_.isEmpty(shadowCRUD.definition) && _.isEmpty(definition)) {
53
- return {};
54
- }
55
-
56
- const queryFields = shadowCRUD.query && toSDL(shadowCRUD.query, resolver.Query, null, 'query');
57
-
58
- const mutationFields =
59
- shadowCRUD.mutation && toSDL(shadowCRUD.mutation, resolver.Mutation, null, 'mutation');
60
-
61
- Object.assign(resolvers, PublicationState.resolver);
62
-
63
- const scalars = Types.getScalars();
64
-
65
- Object.assign(resolvers, scalars);
66
-
67
- const scalarDef = Object.keys(scalars)
68
- .map(key => `scalar ${key}`)
69
- .join('\n');
70
-
71
- // Concatenate.
72
- // Manually defined to avoid exposing all attributes (like password etc.)
73
- let typeDefs = `
74
- ${definition}
75
- ${shadowCRUD.definition}
76
- ${polymorphicSchema.definition}
77
- ${Types.addInput()}
78
-
79
- ${PublicationState.definition}
80
-
81
- type AdminUser {
82
- id: ID!
83
- username: String
84
- firstname: String!
85
- lastname: String!
86
- }
87
-
88
- type Query {
89
- ${queryFields}
90
- ${query}
91
- }
92
-
93
- type Mutation {
94
- ${mutationFields}
95
- ${mutation}
96
- }
97
- ${scalarDef}
98
- `;
99
-
100
- // Build schema.
101
- const schema = makeExecutableSchema({
102
- typeDefs,
103
- resolvers,
104
- });
105
-
106
- const generatedSchema = filterDisabledResolvers(schema, extraResolvers);
107
-
108
- if (strapi.config.environment !== 'production') {
109
- writeGenerateSchema(generatedSchema);
110
- }
111
-
112
- return isFederated ? getFederatedSchema(generatedSchema, resolvers) : generatedSchema;
113
- };
114
-
115
- const getFederatedSchema = (schema, resolvers) =>
116
- buildFederatedSchema([{ typeDefs: gql(graphql.printSchema(schema)), resolvers }]);
117
-
118
- const filterDisabledResolvers = (schema, extraResolvers) =>
119
- filterSchema({
120
- schema,
121
- rootFieldFilter: (operationName, fieldName) => {
122
- const resolver = _.get(extraResolvers[operationName], fieldName, true);
123
-
124
- // resolvers set to false are filtered from the schema
125
- if (resolver === false) {
126
- return false;
127
- }
128
- return true;
129
- },
130
- });
131
-
132
- /**
133
- * Save into a file the readable GraphQL schema.
134
- *
135
- * @return void
136
- */
137
- const writeGenerateSchema = schema => {
138
- const printSchema = graphql.printSchema(schema);
139
- return strapi.fs.writeAppFile('exports/graphql/schema.graphql', printSchema);
140
- };
141
-
142
- const buildResolvers = resolvers => {
143
- // Transform object to only contain function.
144
- return Object.keys(resolvers).reduce((acc, type) => {
145
- if (graphql.isScalarType(resolvers[type])) {
146
- return acc;
147
- }
148
-
149
- return Object.keys(resolvers[type]).reduce((acc, resolverName) => {
150
- const resolverObj = resolvers[type][resolverName];
151
-
152
- // Disabled this query.
153
- if (resolverObj === false) return acc;
154
-
155
- if (_.isFunction(resolverObj)) {
156
- return _.set(acc, [type, resolverName], resolverObj);
157
- }
158
-
159
- switch (type) {
160
- case 'Mutation': {
161
- _.set(acc, [type, resolverName], buildMutation(resolverName, resolverObj));
162
-
163
- break;
164
- }
165
- default: {
166
- _.set(acc, [type, resolverName], buildQuery(resolverName, resolverObj));
167
- break;
168
- }
169
- }
170
-
171
- return acc;
172
- }, acc);
173
- }, {});
174
- };
175
-
176
- module.exports = {
177
- generateSchema,
178
- };