@apollo/gateway 0.300.0-alpha.2 → 2.0.0-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/LICENSE +95 -0
- package/README.md +1 -1
- package/dist/__generated__/graphqlTypes.d.ts +130 -0
- package/dist/__generated__/graphqlTypes.d.ts.map +1 -0
- package/dist/__generated__/graphqlTypes.js +25 -0
- package/dist/__generated__/graphqlTypes.js.map +1 -0
- package/dist/config.d.ts +104 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +47 -0
- package/dist/config.js.map +1 -0
- package/dist/datasources/LocalGraphQLDataSource.d.ts +3 -3
- package/dist/datasources/LocalGraphQLDataSource.d.ts.map +1 -1
- package/dist/datasources/LocalGraphQLDataSource.js +5 -5
- package/dist/datasources/LocalGraphQLDataSource.js.map +1 -1
- package/dist/datasources/RemoteGraphQLDataSource.d.ts +6 -4
- package/dist/datasources/RemoteGraphQLDataSource.d.ts.map +1 -1
- package/dist/datasources/RemoteGraphQLDataSource.js +60 -17
- package/dist/datasources/RemoteGraphQLDataSource.js.map +1 -1
- package/dist/datasources/index.d.ts +1 -1
- package/dist/datasources/index.d.ts.map +1 -1
- package/dist/datasources/index.js +1 -0
- package/dist/datasources/index.js.map +1 -1
- package/dist/datasources/parseCacheControlHeader.d.ts +2 -0
- package/dist/datasources/parseCacheControlHeader.d.ts.map +1 -0
- package/dist/datasources/parseCacheControlHeader.js +16 -0
- package/dist/datasources/parseCacheControlHeader.js.map +1 -0
- package/dist/datasources/types.d.ts +16 -1
- package/dist/datasources/types.d.ts.map +1 -1
- package/dist/datasources/types.js +7 -0
- package/dist/datasources/types.js.map +1 -1
- package/dist/executeQueryPlan.d.ts +2 -1
- package/dist/executeQueryPlan.d.ts.map +1 -1
- package/dist/executeQueryPlan.js +199 -112
- package/dist/executeQueryPlan.js.map +1 -1
- package/dist/index.d.ts +62 -80
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +543 -234
- package/dist/index.js.map +1 -1
- package/dist/loadServicesFromRemoteEndpoint.d.ts +9 -9
- package/dist/loadServicesFromRemoteEndpoint.d.ts.map +1 -1
- package/dist/loadServicesFromRemoteEndpoint.js +13 -8
- package/dist/loadServicesFromRemoteEndpoint.js.map +1 -1
- package/dist/loadSupergraphSdlFromStorage.d.ts +13 -0
- package/dist/loadSupergraphSdlFromStorage.d.ts.map +1 -0
- package/dist/loadSupergraphSdlFromStorage.js +101 -0
- package/dist/loadSupergraphSdlFromStorage.js.map +1 -0
- package/dist/operationContext.d.ts +17 -0
- package/dist/operationContext.d.ts.map +1 -0
- package/dist/operationContext.js +42 -0
- package/dist/operationContext.js.map +1 -0
- package/dist/outOfBandReporter.d.ts +15 -0
- package/dist/outOfBandReporter.d.ts.map +1 -0
- package/dist/outOfBandReporter.js +88 -0
- package/dist/outOfBandReporter.js.map +1 -0
- package/dist/utilities/array.d.ts +1 -2
- package/dist/utilities/array.d.ts.map +1 -1
- package/dist/utilities/array.js +7 -14
- package/dist/utilities/array.js.map +1 -1
- package/dist/utilities/assert.d.ts +2 -0
- package/dist/utilities/assert.d.ts.map +1 -0
- package/dist/utilities/assert.js +10 -0
- package/dist/utilities/assert.js.map +1 -0
- package/dist/utilities/cleanErrorOfInaccessibleNames.d.ts +3 -0
- package/dist/utilities/cleanErrorOfInaccessibleNames.d.ts.map +1 -0
- package/dist/utilities/cleanErrorOfInaccessibleNames.js +27 -0
- package/dist/utilities/cleanErrorOfInaccessibleNames.js.map +1 -0
- package/dist/utilities/deepMerge.js +2 -2
- package/dist/utilities/deepMerge.js.map +1 -1
- package/dist/utilities/graphql.d.ts +1 -4
- package/dist/utilities/graphql.d.ts.map +1 -1
- package/dist/utilities/graphql.js +3 -36
- package/dist/utilities/graphql.js.map +1 -1
- package/dist/utilities/opentelemetry.d.ts +10 -0
- package/dist/utilities/opentelemetry.d.ts.map +1 -0
- package/dist/utilities/opentelemetry.js +19 -0
- package/dist/utilities/opentelemetry.js.map +1 -0
- package/package.json +30 -21
- package/src/__generated__/graphqlTypes.ts +140 -0
- package/src/__mocks__/apollo-server-env.ts +56 -0
- package/src/__mocks__/make-fetch-happen-fetcher.ts +55 -0
- package/src/__mocks__/tsconfig.json +7 -0
- package/src/__tests__/build-query-plan.feature +40 -311
- package/src/__tests__/buildQueryPlan.test.ts +246 -426
- package/src/__tests__/executeQueryPlan.test.ts +1691 -194
- package/src/__tests__/execution-utils.ts +33 -26
- package/src/__tests__/gateway/__snapshots__/opentelemetry.test.ts.snap +195 -0
- package/src/__tests__/gateway/buildService.test.ts +16 -19
- package/src/__tests__/gateway/composedSdl.test.ts +44 -0
- package/src/__tests__/gateway/endToEnd.test.ts +166 -0
- package/src/__tests__/gateway/executor.test.ts +49 -43
- package/src/__tests__/gateway/lifecycle-hooks.test.ts +58 -29
- package/src/__tests__/gateway/opentelemetry.test.ts +123 -0
- package/src/__tests__/gateway/queryPlanCache.test.ts +19 -20
- package/src/__tests__/gateway/reporting.test.ts +76 -55
- package/src/__tests__/integration/abstract-types.test.ts +1086 -22
- package/src/__tests__/integration/aliases.test.ts +5 -6
- package/src/__tests__/integration/boolean.test.ts +40 -38
- package/src/__tests__/integration/complex-key.test.ts +41 -56
- package/src/__tests__/integration/configuration.test.ts +321 -0
- package/src/__tests__/integration/custom-directives.test.ts +61 -46
- package/src/__tests__/integration/fragments.test.ts +8 -2
- package/src/__tests__/integration/list-key.test.ts +2 -2
- package/src/__tests__/integration/logger.test.ts +2 -2
- package/src/__tests__/integration/multiple-key.test.ts +11 -12
- package/src/__tests__/integration/mutations.test.ts +8 -5
- package/src/__tests__/integration/networkRequests.test.ts +447 -289
- package/src/__tests__/integration/nockMocks.ts +95 -66
- package/src/__tests__/integration/provides.test.ts +9 -6
- package/src/__tests__/integration/requires.test.ts +17 -15
- package/src/__tests__/integration/scope.test.ts +557 -0
- package/src/__tests__/integration/unions.test.ts +1 -1
- package/src/__tests__/integration/value-types.test.ts +35 -32
- package/src/__tests__/integration/variables.test.ts +8 -2
- package/src/__tests__/loadServicesFromRemoteEndpoint.test.ts +6 -2
- package/src/__tests__/loadSupergraphSdlFromStorage.test.ts +694 -0
- package/src/__tests__/queryPlanCucumber.test.ts +11 -61
- package/src/__tests__/testSetup.ts +1 -4
- package/src/__tests__/tsconfig.json +2 -1
- package/src/config.ts +225 -0
- package/src/core/__tests__/core.test.ts +412 -0
- package/src/datasources/LocalGraphQLDataSource.ts +9 -10
- package/src/datasources/RemoteGraphQLDataSource.ts +117 -43
- package/src/datasources/__tests__/LocalGraphQLDataSource.test.ts +11 -4
- package/src/datasources/__tests__/RemoteGraphQLDataSource.test.ts +148 -79
- package/src/datasources/__tests__/tsconfig.json +4 -2
- package/src/datasources/index.ts +1 -1
- package/src/datasources/parseCacheControlHeader.ts +43 -0
- package/src/datasources/types.ts +47 -2
- package/src/executeQueryPlan.ts +264 -153
- package/src/index.ts +925 -480
- package/src/loadServicesFromRemoteEndpoint.ts +24 -17
- package/src/loadSupergraphSdlFromStorage.ts +140 -0
- package/src/make-fetch-happen.d.ts +2 -2
- package/src/operationContext.ts +70 -0
- package/src/outOfBandReporter.ts +128 -0
- package/src/utilities/__tests__/cleanErrorOfInaccessibleElements.test.ts +104 -0
- package/src/utilities/__tests__/tsconfig.json +8 -0
- package/src/utilities/array.ts +6 -28
- package/src/utilities/assert.ts +14 -0
- package/src/utilities/cleanErrorOfInaccessibleNames.ts +29 -0
- package/src/utilities/graphql.ts +0 -64
- package/src/utilities/opentelemetry.ts +13 -0
- package/CHANGELOG.md +0 -226
- package/LICENSE.md +0 -20
- package/dist/FieldSet.d.ts +0 -18
- package/dist/FieldSet.d.ts.map +0 -1
- package/dist/FieldSet.js +0 -96
- package/dist/FieldSet.js.map +0 -1
- package/dist/QueryPlan.d.ts +0 -41
- package/dist/QueryPlan.d.ts.map +0 -1
- package/dist/QueryPlan.js +0 -15
- package/dist/QueryPlan.js.map +0 -1
- package/dist/buildQueryPlan.d.ts +0 -44
- package/dist/buildQueryPlan.d.ts.map +0 -1
- package/dist/buildQueryPlan.js +0 -670
- package/dist/buildQueryPlan.js.map +0 -1
- package/dist/loadServicesFromStorage.d.ts +0 -21
- package/dist/loadServicesFromStorage.d.ts.map +0 -1
- package/dist/loadServicesFromStorage.js +0 -64
- package/dist/loadServicesFromStorage.js.map +0 -1
- package/dist/snapshotSerializers/astSerializer.d.ts +0 -3
- package/dist/snapshotSerializers/astSerializer.d.ts.map +0 -1
- package/dist/snapshotSerializers/astSerializer.js +0 -14
- package/dist/snapshotSerializers/astSerializer.js.map +0 -1
- package/dist/snapshotSerializers/index.d.ts +0 -13
- package/dist/snapshotSerializers/index.d.ts.map +0 -1
- package/dist/snapshotSerializers/index.js +0 -15
- package/dist/snapshotSerializers/index.js.map +0 -1
- package/dist/snapshotSerializers/queryPlanSerializer.d.ts +0 -3
- package/dist/snapshotSerializers/queryPlanSerializer.d.ts.map +0 -1
- package/dist/snapshotSerializers/queryPlanSerializer.js +0 -78
- package/dist/snapshotSerializers/queryPlanSerializer.js.map +0 -1
- package/dist/snapshotSerializers/selectionSetSerializer.d.ts +0 -3
- package/dist/snapshotSerializers/selectionSetSerializer.d.ts.map +0 -1
- package/dist/snapshotSerializers/selectionSetSerializer.js +0 -12
- package/dist/snapshotSerializers/selectionSetSerializer.js.map +0 -1
- package/dist/snapshotSerializers/typeSerializer.d.ts +0 -3
- package/dist/snapshotSerializers/typeSerializer.d.ts.map +0 -1
- package/dist/snapshotSerializers/typeSerializer.js +0 -12
- package/dist/snapshotSerializers/typeSerializer.js.map +0 -1
- package/dist/utilities/MultiMap.d.ts +0 -4
- package/dist/utilities/MultiMap.d.ts.map +0 -1
- package/dist/utilities/MultiMap.js +0 -17
- package/dist/utilities/MultiMap.js.map +0 -1
- package/src/FieldSet.ts +0 -169
- package/src/QueryPlan.ts +0 -57
- package/src/__tests__/matchers/toCallService.ts +0 -105
- package/src/__tests__/matchers/toHaveBeenCalledBefore.ts +0 -40
- package/src/__tests__/matchers/toHaveFetched.ts +0 -81
- package/src/__tests__/matchers/toMatchAST.ts +0 -64
- package/src/buildQueryPlan.ts +0 -1190
- package/src/loadServicesFromStorage.ts +0 -170
- package/src/snapshotSerializers/astSerializer.ts +0 -21
- package/src/snapshotSerializers/index.ts +0 -21
- package/src/snapshotSerializers/queryPlanSerializer.ts +0 -144
- package/src/snapshotSerializers/selectionSetSerializer.ts +0 -13
- package/src/snapshotSerializers/typeSerializer.ts +0 -11
- package/src/utilities/MultiMap.ts +0 -11
|
@@ -3,23 +3,25 @@ import {
|
|
|
3
3
|
GraphQLResponse,
|
|
4
4
|
ValueOrPromise,
|
|
5
5
|
GraphQLRequest,
|
|
6
|
+
CacheHint,
|
|
7
|
+
CacheScope,
|
|
8
|
+
CachePolicy,
|
|
6
9
|
} from 'apollo-server-types';
|
|
7
10
|
import {
|
|
8
11
|
ApolloError,
|
|
9
12
|
AuthenticationError,
|
|
10
13
|
ForbiddenError,
|
|
11
14
|
} from 'apollo-server-errors';
|
|
12
|
-
import {
|
|
13
|
-
fetch,
|
|
14
|
-
Request,
|
|
15
|
-
Headers,
|
|
16
|
-
Response,
|
|
17
|
-
} from 'apollo-server-env';
|
|
15
|
+
import { fetch, Request, Headers, Response } from 'apollo-server-env';
|
|
18
16
|
import { isObject } from '../utilities/predicates';
|
|
19
|
-
import { GraphQLDataSource } from './types';
|
|
17
|
+
import { GraphQLDataSource, GraphQLDataSourceProcessOptions, GraphQLDataSourceRequestKind } from './types';
|
|
20
18
|
import createSHA from 'apollo-server-core/dist/utils/createSHA';
|
|
19
|
+
import { parseCacheControlHeader } from './parseCacheControlHeader';
|
|
21
20
|
|
|
22
|
-
export class RemoteGraphQLDataSource<
|
|
21
|
+
export class RemoteGraphQLDataSource<
|
|
22
|
+
TContext extends Record<string, any> = Record<string, any>,
|
|
23
|
+
> implements GraphQLDataSource<TContext>
|
|
24
|
+
{
|
|
23
25
|
fetcher: typeof fetch = fetch;
|
|
24
26
|
|
|
25
27
|
constructor(
|
|
@@ -54,12 +56,25 @@ export class RemoteGraphQLDataSource<TContext extends Record<string, any> = Reco
|
|
|
54
56
|
*/
|
|
55
57
|
apq: boolean = false;
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Should cache-control response headers from subgraphs affect the operation's
|
|
61
|
+
* cache policy? If it shouldn't, set this to false.
|
|
62
|
+
*/
|
|
63
|
+
honorSubgraphCacheControlHeader: boolean = true;
|
|
64
|
+
|
|
65
|
+
async process(
|
|
66
|
+
options: GraphQLDataSourceProcessOptions<TContext>,
|
|
67
|
+
): Promise<GraphQLResponse> {
|
|
68
|
+
const { request, context: originalContext } = options;
|
|
69
|
+
// Deal with a bit of a hairy situation in typings: when doing health checks
|
|
70
|
+
// and schema checks we always pass in `{}` as the context even though it's
|
|
71
|
+
// not really guaranteed to be a `TContext`, and then we pass it to various
|
|
72
|
+
// methods on this object. The reason this "works" is that the DataSourceMap
|
|
73
|
+
// and Service types aren't generic-ized on TContext at all (so `{}` is in
|
|
74
|
+
// practice always legal there)... ie, the genericness of this class is
|
|
75
|
+
// questionable in the first place.
|
|
76
|
+
const context = originalContext as TContext;
|
|
77
|
+
|
|
63
78
|
// Respect incoming http headers (eg, apollo-federation-include-trace).
|
|
64
79
|
const headers = (request.http && request.http.headers) || new Headers();
|
|
65
80
|
headers.set('Content-Type', 'application/json');
|
|
@@ -71,25 +86,28 @@ export class RemoteGraphQLDataSource<TContext extends Record<string, any> = Reco
|
|
|
71
86
|
};
|
|
72
87
|
|
|
73
88
|
if (this.willSendRequest) {
|
|
74
|
-
await this.willSendRequest(
|
|
89
|
+
await this.willSendRequest(options);
|
|
75
90
|
}
|
|
76
91
|
|
|
77
92
|
if (!request.query) {
|
|
78
|
-
throw new Error(
|
|
93
|
+
throw new Error('Missing query');
|
|
79
94
|
}
|
|
80
95
|
|
|
81
|
-
const apqHash = createSHA('sha256')
|
|
82
|
-
.update(request.query)
|
|
83
|
-
.digest('hex');
|
|
84
|
-
|
|
85
96
|
const { query, ...requestWithoutQuery } = request;
|
|
86
97
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
98
|
+
// Special handling of cache-control headers in response. Requires
|
|
99
|
+
// Apollo Server 3, so we check to make sure the method we want is
|
|
100
|
+
// there.
|
|
101
|
+
const overallCachePolicy =
|
|
102
|
+
this.honorSubgraphCacheControlHeader &&
|
|
103
|
+
options.kind === GraphQLDataSourceRequestKind.INCOMING_OPERATION &&
|
|
104
|
+
options.incomingRequestContext.overallCachePolicy?.restrict
|
|
105
|
+
? options.incomingRequestContext.overallCachePolicy
|
|
106
|
+
: null;
|
|
91
107
|
|
|
92
108
|
if (this.apq) {
|
|
109
|
+
const apqHash = createSHA('sha256').update(request.query).digest('hex');
|
|
110
|
+
|
|
93
111
|
// Take the original extensions and extend them with
|
|
94
112
|
// the necessary "extensions" for APQ handshaking.
|
|
95
113
|
requestWithoutQuery.extensions = {
|
|
@@ -100,17 +118,25 @@ export class RemoteGraphQLDataSource<TContext extends Record<string, any> = Reco
|
|
|
100
118
|
},
|
|
101
119
|
};
|
|
102
120
|
|
|
103
|
-
const apqOptimisticResponse =
|
|
104
|
-
|
|
121
|
+
const apqOptimisticResponse = await this.sendRequest(
|
|
122
|
+
requestWithoutQuery,
|
|
123
|
+
context,
|
|
124
|
+
);
|
|
105
125
|
|
|
106
126
|
// If we didn't receive notice to retry with APQ, then let's
|
|
107
127
|
// assume this is the best result we'll get and return it!
|
|
108
128
|
if (
|
|
109
129
|
!apqOptimisticResponse.errors ||
|
|
110
|
-
!apqOptimisticResponse.errors.find(
|
|
111
|
-
error.message === 'PersistedQueryNotFound'
|
|
130
|
+
!apqOptimisticResponse.errors.find(
|
|
131
|
+
(error) => error.message === 'PersistedQueryNotFound',
|
|
132
|
+
)
|
|
112
133
|
) {
|
|
113
|
-
return respond(
|
|
134
|
+
return this.respond({
|
|
135
|
+
response: apqOptimisticResponse,
|
|
136
|
+
request: requestWithoutQuery,
|
|
137
|
+
context,
|
|
138
|
+
overallCachePolicy,
|
|
139
|
+
});
|
|
114
140
|
}
|
|
115
141
|
}
|
|
116
142
|
|
|
@@ -122,34 +148,43 @@ export class RemoteGraphQLDataSource<TContext extends Record<string, any> = Reco
|
|
|
122
148
|
...requestWithoutQuery,
|
|
123
149
|
};
|
|
124
150
|
const response = await this.sendRequest(requestWithQuery, context);
|
|
125
|
-
return respond(
|
|
151
|
+
return this.respond({
|
|
152
|
+
response,
|
|
153
|
+
request: requestWithQuery,
|
|
154
|
+
context,
|
|
155
|
+
overallCachePolicy,
|
|
156
|
+
});
|
|
126
157
|
}
|
|
127
158
|
|
|
128
159
|
private async sendRequest(
|
|
129
160
|
request: GraphQLRequest,
|
|
130
161
|
context: TContext,
|
|
131
162
|
): Promise<GraphQLResponse> {
|
|
132
|
-
|
|
133
163
|
// This would represent an internal programming error since this shouldn't
|
|
134
164
|
// be possible in the way that this method is invoked right now.
|
|
135
165
|
if (!request.http) {
|
|
136
|
-
throw new Error("Internal error: Only 'http' requests are supported.")
|
|
166
|
+
throw new Error("Internal error: Only 'http' requests are supported.");
|
|
137
167
|
}
|
|
138
168
|
|
|
139
169
|
// We don't want to serialize the `http` properties into the body that is
|
|
140
170
|
// being transmitted. Instead, we want those to be used to indicate what
|
|
141
171
|
// we're accessing (e.g. url) and what we access it with (e.g. headers).
|
|
142
172
|
const { http, ...requestWithoutHttp } = request;
|
|
173
|
+
const stringifiedRequestWithoutHttp = JSON.stringify(requestWithoutHttp);
|
|
143
174
|
const fetchRequest = new Request(http.url, {
|
|
144
175
|
...http,
|
|
145
|
-
body:
|
|
176
|
+
body: stringifiedRequestWithoutHttp,
|
|
146
177
|
});
|
|
147
178
|
|
|
148
179
|
let fetchResponse: Response | undefined;
|
|
149
180
|
|
|
150
181
|
try {
|
|
151
182
|
// Use our local `fetcher` to allow for fetch injection
|
|
152
|
-
|
|
183
|
+
// Use the fetcher's `Request` implementation for compatibility
|
|
184
|
+
fetchResponse = await this.fetcher(http.url, {
|
|
185
|
+
...http,
|
|
186
|
+
body: stringifiedRequestWithoutHttp,
|
|
187
|
+
});
|
|
153
188
|
|
|
154
189
|
if (!fetchResponse.ok) {
|
|
155
190
|
throw await this.errorFromResponse(fetchResponse);
|
|
@@ -166,29 +201,68 @@ export class RemoteGraphQLDataSource<TContext extends Record<string, any> = Reco
|
|
|
166
201
|
http: fetchResponse,
|
|
167
202
|
};
|
|
168
203
|
} catch (error) {
|
|
169
|
-
this.didEncounterError(error, fetchRequest, fetchResponse);
|
|
204
|
+
this.didEncounterError(error, fetchRequest, fetchResponse, context);
|
|
170
205
|
throw error;
|
|
171
206
|
}
|
|
172
207
|
}
|
|
173
208
|
|
|
174
209
|
public willSendRequest?(
|
|
175
|
-
|
|
176
|
-
GraphQLRequestContext<TContext>,
|
|
177
|
-
'request' | 'context'
|
|
178
|
-
>,
|
|
210
|
+
options: GraphQLDataSourceProcessOptions<TContext>,
|
|
179
211
|
): ValueOrPromise<void>;
|
|
180
212
|
|
|
213
|
+
private async respond({
|
|
214
|
+
response,
|
|
215
|
+
request,
|
|
216
|
+
context,
|
|
217
|
+
overallCachePolicy,
|
|
218
|
+
}: {
|
|
219
|
+
response: GraphQLResponse;
|
|
220
|
+
request: GraphQLRequest;
|
|
221
|
+
context: TContext;
|
|
222
|
+
overallCachePolicy: CachePolicy | null;
|
|
223
|
+
}): Promise<GraphQLResponse> {
|
|
224
|
+
const processedResponse =
|
|
225
|
+
typeof this.didReceiveResponse === 'function'
|
|
226
|
+
? await this.didReceiveResponse({ response, request, context })
|
|
227
|
+
: response;
|
|
228
|
+
|
|
229
|
+
if (overallCachePolicy) {
|
|
230
|
+
const parsed = parseCacheControlHeader(
|
|
231
|
+
response.http?.headers.get('cache-control'),
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
// If the subgraph does not specify a max-age, we assume its response (and
|
|
235
|
+
// thus the overall response) is uncacheable. (If you don't like this, you
|
|
236
|
+
// can tweak the `cache-control` header in your `didReceiveResponse`
|
|
237
|
+
// method.)
|
|
238
|
+
const hint: CacheHint = { maxAge: 0 };
|
|
239
|
+
const maxAge = parsed['max-age'];
|
|
240
|
+
if (typeof maxAge === 'string' && maxAge.match(/^[0-9]+$/)) {
|
|
241
|
+
hint.maxAge = +maxAge;
|
|
242
|
+
}
|
|
243
|
+
if (parsed['private'] === true) {
|
|
244
|
+
hint.scope = CacheScope.Private;
|
|
245
|
+
}
|
|
246
|
+
if (parsed['public'] === true) {
|
|
247
|
+
hint.scope = CacheScope.Public;
|
|
248
|
+
}
|
|
249
|
+
overallCachePolicy.restrict(hint);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return processedResponse;
|
|
253
|
+
}
|
|
254
|
+
|
|
181
255
|
public didReceiveResponse?(
|
|
182
|
-
requestContext: Required<
|
|
183
|
-
GraphQLRequestContext<TContext>,
|
|
184
|
-
'request' | 'response' | 'context'>
|
|
256
|
+
requestContext: Required<
|
|
257
|
+
Pick<GraphQLRequestContext<TContext>, 'request' | 'response' | 'context'>
|
|
185
258
|
>,
|
|
186
259
|
): ValueOrPromise<GraphQLResponse>;
|
|
187
260
|
|
|
188
261
|
public didEncounterError(
|
|
189
262
|
error: Error,
|
|
190
263
|
_fetchRequest: Request,
|
|
191
|
-
_fetchResponse?: Response
|
|
264
|
+
_fetchResponse?: Response,
|
|
265
|
+
_context?: TContext,
|
|
192
266
|
) {
|
|
193
267
|
throw error;
|
|
194
268
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { LocalGraphQLDataSource } from '../LocalGraphQLDataSource';
|
|
2
|
-
import {
|
|
2
|
+
import { buildSubgraphSchema } from '@apollo/subgraph';
|
|
3
3
|
import gql from 'graphql-tag';
|
|
4
|
+
import { GraphQLResolverMap } from 'apollo-graphql';
|
|
5
|
+
import { GraphQLRequestContext } from 'apollo-server-types';
|
|
6
|
+
import { GraphQLDataSourceRequestKind } from '../types';
|
|
4
7
|
|
|
5
8
|
describe('constructing requests', () => {
|
|
6
9
|
it('accepts context', async () => {
|
|
@@ -13,7 +16,7 @@ describe('constructing requests', () => {
|
|
|
13
16
|
name: String!
|
|
14
17
|
}
|
|
15
18
|
`;
|
|
16
|
-
const resolvers = {
|
|
19
|
+
const resolvers: GraphQLResolverMap<{ userId: number }> = {
|
|
17
20
|
Query: {
|
|
18
21
|
me(_, __, { userId }) {
|
|
19
22
|
const users = [
|
|
@@ -24,18 +27,22 @@ describe('constructing requests', () => {
|
|
|
24
27
|
name: 'someoneElse',
|
|
25
28
|
},
|
|
26
29
|
];
|
|
27
|
-
return users.find(user => user.id === userId);
|
|
30
|
+
return users.find((user) => user.id === userId);
|
|
28
31
|
},
|
|
29
32
|
},
|
|
30
33
|
};
|
|
31
|
-
const schema =
|
|
34
|
+
const schema = buildSubgraphSchema([{ typeDefs, resolvers }]);
|
|
32
35
|
|
|
33
36
|
const DataSource = new LocalGraphQLDataSource(schema);
|
|
34
37
|
|
|
35
38
|
const { data } = await DataSource.process({
|
|
39
|
+
kind: GraphQLDataSourceRequestKind.INCOMING_OPERATION,
|
|
36
40
|
request: {
|
|
37
41
|
query: '{ me { name } }',
|
|
38
42
|
},
|
|
43
|
+
incomingRequestContext: {
|
|
44
|
+
context: { userId: 2 },
|
|
45
|
+
} as GraphQLRequestContext<{userId: number}>,
|
|
39
46
|
context: { userId: 2 },
|
|
40
47
|
});
|
|
41
48
|
|