@apollo/gateway 2.1.2-alpha.0 → 2.1.2-alpha.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.
- package/dist/schema-helper/addExtensions.js.map +1 -1
- package/dist/typings/graphql.d.ts +5 -28
- package/dist/typings/graphql.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/__tests__/executeQueryPlan.test.ts +189 -0
- package/src/__tests__/gateway/lifecycle-hooks.test.ts +1 -1
- package/src/schema-helper/__tests__/addExtensions.test.ts +9 -4
- package/src/schema-helper/addExtensions.ts +2 -2
- package/src/typings/graphql.ts +4 -36
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"addExtensions.js","sourceRoot":"","sources":["../../src/schema-helper/addExtensions.ts"],"names":[],"mappings":";;;AAGA,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAElD,SAAgB,aAAa,CAAC,MAAqB;;IACjD,MAAM,eAAe,
|
|
1
|
+
{"version":3,"file":"addExtensions.js","sourceRoot":"","sources":["../../src/schema-helper/addExtensions.ts"],"names":[],"mappings":";;;AAGA,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAElD,SAAgB,aAAa,CAAC,MAAqB;;IACjD,MAAM,eAAe,GAAkC,MAAA,MAAM,CAAC,UAAU,mCAAI,EAAE,CAAC;IAC/E,MAAM,eAAe,GAAG,MAAA,eAAe,aAAf,eAAe,uBAAf,eAAe,CAAE,MAAM,mCAAI,EAAE,CAAC;IACtD,MAAM,gBAAgB,GAAG,MAAA,eAAe,aAAf,eAAe,uBAAf,eAAe,CAAE,OAAO,mCAAI,EAAE,CAAC;IAExD,MAAM,CAAC,UAAU,GAAG;QAClB,GAAG,MAAM,CAAC,UAAU;QACpB,MAAM,EAAE;YACN,GAAG,eAAe;YAClB,OAAO,EAAE;gBACP,GAAG,gBAAgB;gBACnB,OAAO;aACR;SACF;KACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAjBD,sCAiBC"}
|
|
@@ -1,34 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
declare type GraphQLReferenceResolver<TContext> = (reference: object, context: TContext, info: GraphQLResolveInfo) => any;
|
|
3
|
-
interface ApolloSubgraphExtensions<TContext> {
|
|
4
|
-
resolveReference?: GraphQLReferenceResolver<TContext>;
|
|
5
|
-
}
|
|
1
|
+
import { GraphQLSchemaExtensions } from 'graphql';
|
|
6
2
|
interface ApolloGatewayExtensions {
|
|
7
3
|
version?: String;
|
|
8
4
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
interface GraphQLInterfaceTypeExtensions<_TSource = any, _TContext = any> {
|
|
16
|
-
apollo?: {
|
|
17
|
-
subgraph?: ApolloSubgraphExtensions<_TContext>;
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
interface GraphQLUnionTypeExtensions<_TSource = any, _TContext = any> {
|
|
21
|
-
apollo?: {
|
|
22
|
-
subgraph?: ApolloSubgraphExtensions<_TContext>;
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
declare module 'graphql/type/schema' {
|
|
27
|
-
interface GraphQLSchemaExtensions {
|
|
28
|
-
apollo?: {
|
|
29
|
-
gateway?: ApolloGatewayExtensions;
|
|
30
|
-
};
|
|
31
|
-
}
|
|
5
|
+
export interface ApolloGraphQLSchemaExtensions extends GraphQLSchemaExtensions {
|
|
6
|
+
apollo?: {
|
|
7
|
+
gateway?: ApolloGatewayExtensions;
|
|
8
|
+
};
|
|
32
9
|
}
|
|
33
10
|
export {};
|
|
34
11
|
//# sourceMappingURL=graphql.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphql.d.ts","sourceRoot":"","sources":["../../src/typings/graphql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"graphql.d.ts","sourceRoot":"","sources":["../../src/typings/graphql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAElD,UAAU,uBAAuB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,6BAA8B,SAAQ,uBAAuB;IAC5E,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,uBAAuB,CAAC;KACnC,CAAA;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apollo/gateway",
|
|
3
|
-
"version": "2.1.2-alpha.
|
|
3
|
+
"version": "2.1.2-alpha.2",
|
|
4
4
|
"description": "Apollo Gateway",
|
|
5
5
|
"author": "Apollo <packages@apollographql.com>",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"access": "public"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@apollo/composition": "^2.1.2-alpha.
|
|
29
|
-
"@apollo/federation-internals": "^2.1.2-alpha.
|
|
30
|
-
"@apollo/query-planner": "^2.1.2-alpha.
|
|
28
|
+
"@apollo/composition": "^2.1.2-alpha.2",
|
|
29
|
+
"@apollo/federation-internals": "^2.1.2-alpha.2",
|
|
30
|
+
"@apollo/query-planner": "^2.1.2-alpha.2",
|
|
31
31
|
"@apollo/server-gateway-interface": "^1.0.2",
|
|
32
32
|
"@apollo/utils.createhash": "^1.1.0",
|
|
33
33
|
"@apollo/utils.fetcher": "^1.1.0",
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"graphql": "^16.5.0"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "c7bb87702c5913f5a0ecc5c2a28d2f7228e2988c"
|
|
51
51
|
}
|
|
@@ -3072,6 +3072,195 @@ describe('executeQueryPlan', () => {
|
|
|
3072
3072
|
}
|
|
3073
3073
|
`);
|
|
3074
3074
|
});
|
|
3075
|
+
|
|
3076
|
+
test.each([
|
|
3077
|
+
{
|
|
3078
|
+
name: 'nullable argument, no default, no value passed',
|
|
3079
|
+
argNullable: true,
|
|
3080
|
+
defaultValue: undefined,
|
|
3081
|
+
valuePassed: undefined,
|
|
3082
|
+
},
|
|
3083
|
+
{
|
|
3084
|
+
name: 'nullable argument, no default, value passed',
|
|
3085
|
+
argNullable: true,
|
|
3086
|
+
defaultValue: undefined,
|
|
3087
|
+
valuePassed: 42,
|
|
3088
|
+
},
|
|
3089
|
+
{
|
|
3090
|
+
name: 'nullable argument, default, no value passed',
|
|
3091
|
+
argNullable: true,
|
|
3092
|
+
defaultValue: 24,
|
|
3093
|
+
valuePassed: undefined,
|
|
3094
|
+
},
|
|
3095
|
+
{
|
|
3096
|
+
name: 'nullable argument, default, value passed',
|
|
3097
|
+
argNullable: true,
|
|
3098
|
+
defaultValue: 24,
|
|
3099
|
+
valuePassed: 42,
|
|
3100
|
+
},
|
|
3101
|
+
{
|
|
3102
|
+
name: 'non-nullable argument, no default, no value passed',
|
|
3103
|
+
argNullable: false,
|
|
3104
|
+
defaultValue: undefined,
|
|
3105
|
+
valuePassed: undefined,
|
|
3106
|
+
},
|
|
3107
|
+
{
|
|
3108
|
+
name: 'non-nullable argument, no default, value passed',
|
|
3109
|
+
argNullable: false,
|
|
3110
|
+
defaultValue: undefined,
|
|
3111
|
+
valuePassed: 42,
|
|
3112
|
+
},
|
|
3113
|
+
{
|
|
3114
|
+
name: 'non-nullable argument, default, no value passed',
|
|
3115
|
+
argNullable: false,
|
|
3116
|
+
defaultValue: 24,
|
|
3117
|
+
valuePassed: undefined,
|
|
3118
|
+
},
|
|
3119
|
+
{
|
|
3120
|
+
name: 'non-nullable argument, default, value passed',
|
|
3121
|
+
argNullable: false,
|
|
3122
|
+
defaultValue: 24,
|
|
3123
|
+
valuePassed: 42,
|
|
3124
|
+
},
|
|
3125
|
+
])('requires on field with argument: $name', async ({
|
|
3126
|
+
argNullable,
|
|
3127
|
+
defaultValue,
|
|
3128
|
+
valuePassed,
|
|
3129
|
+
}: {
|
|
3130
|
+
argNullable: boolean,
|
|
3131
|
+
defaultValue?: number,
|
|
3132
|
+
valuePassed?: number,
|
|
3133
|
+
}) => {
|
|
3134
|
+
|
|
3135
|
+
const argType = `Int${argNullable ? '' : '!'}${defaultValue ? ` = ${defaultValue}` : ''}`;
|
|
3136
|
+
const s1 = {
|
|
3137
|
+
name: 'S1',
|
|
3138
|
+
typeDefs: gql`
|
|
3139
|
+
type T @key(fields: "id") {
|
|
3140
|
+
id: Int!
|
|
3141
|
+
x(opt: ${argType}): String!
|
|
3142
|
+
}
|
|
3143
|
+
`,
|
|
3144
|
+
resolvers: {
|
|
3145
|
+
T: {
|
|
3146
|
+
__resolveReference(ref: { id: number}) {
|
|
3147
|
+
return ref;
|
|
3148
|
+
},
|
|
3149
|
+
x(_: any, args: any) {
|
|
3150
|
+
return `args: ${JSON.stringify(args)}`;
|
|
3151
|
+
}
|
|
3152
|
+
},
|
|
3153
|
+
}
|
|
3154
|
+
}
|
|
3155
|
+
|
|
3156
|
+
const s2 = {
|
|
3157
|
+
name: 'S2',
|
|
3158
|
+
typeDefs: gql`
|
|
3159
|
+
type Query {
|
|
3160
|
+
t: T
|
|
3161
|
+
}
|
|
3162
|
+
|
|
3163
|
+
type T @key(fields: "id") {
|
|
3164
|
+
id: Int!
|
|
3165
|
+
x(opt: ${argType}): String! @external
|
|
3166
|
+
y: String @requires(fields: "x${valuePassed ? `(opt: ${valuePassed})` : ''}")
|
|
3167
|
+
}
|
|
3168
|
+
|
|
3169
|
+
`,
|
|
3170
|
+
resolvers: {
|
|
3171
|
+
Query: {
|
|
3172
|
+
t() {
|
|
3173
|
+
return {id: 0};
|
|
3174
|
+
},
|
|
3175
|
+
},
|
|
3176
|
+
T: {
|
|
3177
|
+
__resolveReference(ref: { id: number }) {
|
|
3178
|
+
// the ref has already the id and f1 is a require is triggered, and we resolve f2 below
|
|
3179
|
+
return ref;
|
|
3180
|
+
},
|
|
3181
|
+
y(parent: any) {
|
|
3182
|
+
return `x: ${parent.x}`;
|
|
3183
|
+
}
|
|
3184
|
+
}
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3187
|
+
|
|
3188
|
+
if (!argNullable && !defaultValue && !valuePassed) {
|
|
3189
|
+
// We test all combination of `argNullable`, `defaultValue` set/unset and `valuePassed` set/unset, and all should be allowed
|
|
3190
|
+
// except if the value is non-nullable and has neither a default nor a value passed. In that case, just ensure the error message
|
|
3191
|
+
// is meaningful.
|
|
3192
|
+
expect(() => getFederatedTestingSchema([ s1, s2 ])).toThrowError(
|
|
3193
|
+
'[S2] On field "T.y", for @requires(fields: "x"): Missing mandatory value for argument "opt" of field "T.x" in selection "x"'
|
|
3194
|
+
);
|
|
3195
|
+
return;
|
|
3196
|
+
}
|
|
3197
|
+
|
|
3198
|
+
const { serviceMap, schema, queryPlanner} = getFederatedTestingSchema([ s1, s2 ]);
|
|
3199
|
+
|
|
3200
|
+
const operation = parseOp(`
|
|
3201
|
+
{
|
|
3202
|
+
t {
|
|
3203
|
+
y
|
|
3204
|
+
}
|
|
3205
|
+
}
|
|
3206
|
+
`, schema);
|
|
3207
|
+
const queryPlan = buildPlan(operation, queryPlanner);
|
|
3208
|
+
expect(queryPlan).toMatchInlineSnapshot(`
|
|
3209
|
+
QueryPlan {
|
|
3210
|
+
Sequence {
|
|
3211
|
+
Fetch(service: "S2") {
|
|
3212
|
+
{
|
|
3213
|
+
t {
|
|
3214
|
+
__typename
|
|
3215
|
+
id
|
|
3216
|
+
}
|
|
3217
|
+
}
|
|
3218
|
+
},
|
|
3219
|
+
Flatten(path: "t") {
|
|
3220
|
+
Fetch(service: "S1") {
|
|
3221
|
+
{
|
|
3222
|
+
... on T {
|
|
3223
|
+
__typename
|
|
3224
|
+
id
|
|
3225
|
+
}
|
|
3226
|
+
} =>
|
|
3227
|
+
{
|
|
3228
|
+
... on T {
|
|
3229
|
+
x${valuePassed ? `(opt: ${valuePassed})` : ''}
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
},
|
|
3233
|
+
},
|
|
3234
|
+
Flatten(path: "t") {
|
|
3235
|
+
Fetch(service: "S2") {
|
|
3236
|
+
{
|
|
3237
|
+
... on T {
|
|
3238
|
+
__typename
|
|
3239
|
+
x
|
|
3240
|
+
id
|
|
3241
|
+
}
|
|
3242
|
+
} =>
|
|
3243
|
+
{
|
|
3244
|
+
... on T {
|
|
3245
|
+
y
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
},
|
|
3249
|
+
},
|
|
3250
|
+
},
|
|
3251
|
+
}
|
|
3252
|
+
`);
|
|
3253
|
+
|
|
3254
|
+
const response = await executePlan(queryPlan, operation, undefined, schema, serviceMap);
|
|
3255
|
+
expect(response.errors).toBeUndefined();
|
|
3256
|
+
expect(response.data).toMatchInlineSnapshot(`
|
|
3257
|
+
Object {
|
|
3258
|
+
"t": Object {
|
|
3259
|
+
"y": "x: args: {${valuePassed ? `\\"opt\\":${valuePassed}` : (defaultValue ? `\\"opt\\":${defaultValue}` : '')}}",
|
|
3260
|
+
},
|
|
3261
|
+
}
|
|
3262
|
+
`);
|
|
3263
|
+
});
|
|
3075
3264
|
});
|
|
3076
3265
|
|
|
3077
3266
|
describe('@key', () => {
|
|
@@ -147,7 +147,7 @@ describe('lifecycle hooks', () => {
|
|
|
147
147
|
// the supergraph (even just formatting differences), this ID will change
|
|
148
148
|
// and this test will have to updated.
|
|
149
149
|
expect(secondCall[0]!.compositionId).toEqual(
|
|
150
|
-
'
|
|
150
|
+
'55f11e687010f75c791b917d9a46745b967c5b19d20443463ed075e500bff6c8',
|
|
151
151
|
);
|
|
152
152
|
// second call should have previous info in the second arg
|
|
153
153
|
expect(secondCall[1]!.compositionId).toEqual(expectedFirstId);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { buildSchema } from 'graphql';
|
|
2
2
|
import { addExtensions } from '../addExtensions';
|
|
3
|
+
import { ApolloGraphQLSchemaExtensions } from '../../typings/graphql';
|
|
3
4
|
const { version } = require('../../../package.json');
|
|
4
5
|
|
|
5
6
|
describe('addExtensions', () => {
|
|
@@ -7,7 +8,8 @@ describe('addExtensions', () => {
|
|
|
7
8
|
it('adds gateway extensions to a schema', async () => {
|
|
8
9
|
const schema = buildSchema('type Query { hello: String }');
|
|
9
10
|
expect(schema.extensions).toEqual({});
|
|
10
|
-
|
|
11
|
+
const actualExtensions: ApolloGraphQLSchemaExtensions = addExtensions(schema).extensions;
|
|
12
|
+
expect(actualExtensions).toEqual({ apollo: { gateway: { version: version } } });
|
|
11
13
|
});
|
|
12
14
|
|
|
13
15
|
it('does not delete existing extensions', async () => {
|
|
@@ -21,7 +23,8 @@ describe('addExtensions', () => {
|
|
|
21
23
|
}
|
|
22
24
|
}
|
|
23
25
|
};
|
|
24
|
-
|
|
26
|
+
const actualExtensions: ApolloGraphQLSchemaExtensions = addExtensions(schema).extensions;
|
|
27
|
+
expect(actualExtensions).toEqual({
|
|
25
28
|
foo: 'bar',
|
|
26
29
|
apollo: {
|
|
27
30
|
gateway: {
|
|
@@ -37,7 +40,8 @@ describe('addExtensions', () => {
|
|
|
37
40
|
schema.extensions = {
|
|
38
41
|
apollo: undefined
|
|
39
42
|
};
|
|
40
|
-
|
|
43
|
+
const actualExtensions: ApolloGraphQLSchemaExtensions = addExtensions(schema).extensions;
|
|
44
|
+
expect(actualExtensions).toEqual({
|
|
41
45
|
apollo: {
|
|
42
46
|
gateway: {
|
|
43
47
|
version: version
|
|
@@ -54,7 +58,8 @@ describe('addExtensions', () => {
|
|
|
54
58
|
gateway: undefined
|
|
55
59
|
}
|
|
56
60
|
};
|
|
57
|
-
|
|
61
|
+
const actualExtensions: ApolloGraphQLSchemaExtensions = addExtensions(schema).extensions;
|
|
62
|
+
expect(actualExtensions).toEqual({
|
|
58
63
|
apollo: {
|
|
59
64
|
gateway: {
|
|
60
65
|
version: version
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { GraphQLSchema } from 'graphql';
|
|
2
|
-
import {
|
|
2
|
+
import { ApolloGraphQLSchemaExtensions } from '../typings/graphql';
|
|
3
3
|
|
|
4
4
|
const { version } = require('../../package.json');
|
|
5
5
|
|
|
6
6
|
export function addExtensions(schema: GraphQLSchema): GraphQLSchema {
|
|
7
|
-
const schemaExtension = schema.extensions
|
|
7
|
+
const schemaExtension: ApolloGraphQLSchemaExtensions = schema.extensions ?? {};
|
|
8
8
|
const apolloExtension = schemaExtension?.apollo ?? {};
|
|
9
9
|
const gatewayExtension = apolloExtension?.gateway ?? {};
|
|
10
10
|
|
package/src/typings/graphql.ts
CHANGED
|
@@ -1,43 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
type GraphQLReferenceResolver<TContext> = (
|
|
4
|
-
reference: object,
|
|
5
|
-
context: TContext,
|
|
6
|
-
info: GraphQLResolveInfo,
|
|
7
|
-
) => any;
|
|
8
|
-
|
|
9
|
-
interface ApolloSubgraphExtensions<TContext> {
|
|
10
|
-
resolveReference?: GraphQLReferenceResolver<TContext>;
|
|
11
|
-
}
|
|
1
|
+
import { GraphQLSchemaExtensions } from 'graphql';
|
|
12
2
|
|
|
13
3
|
interface ApolloGatewayExtensions {
|
|
14
4
|
version?: String;
|
|
15
5
|
}
|
|
16
6
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
subgraph?: ApolloSubgraphExtensions<_TContext>;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
interface GraphQLInterfaceTypeExtensions<_TSource = any, _TContext = any> {
|
|
25
|
-
apollo?: {
|
|
26
|
-
subgraph?: ApolloSubgraphExtensions<_TContext>;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
interface GraphQLUnionTypeExtensions<_TSource = any, _TContext = any> {
|
|
31
|
-
apollo?: {
|
|
32
|
-
subgraph?: ApolloSubgraphExtensions<_TContext>;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
declare module 'graphql/type/schema' {
|
|
38
|
-
interface GraphQLSchemaExtensions {
|
|
39
|
-
apollo?: {
|
|
40
|
-
gateway?: ApolloGatewayExtensions;
|
|
41
|
-
}
|
|
7
|
+
export interface ApolloGraphQLSchemaExtensions extends GraphQLSchemaExtensions {
|
|
8
|
+
apollo?: {
|
|
9
|
+
gateway?: ApolloGatewayExtensions;
|
|
42
10
|
}
|
|
43
11
|
}
|