UNPKG

11.6 kBJavaScriptView Raw
1"use strict";
2var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4 return new (P || (P = Promise))(function (resolve, reject) {
5 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8 step((generator = generator.apply(thisArg, _arguments || [])).next());
9 });
10};
11Object.defineProperty(exports, "__esModule", { value: true });
12exports.cloneObject = exports.processHTTPRequest = exports.runHttpQuery = exports.throwHttpGraphQLError = exports.HttpQueryError = void 0;
13const apollo_server_env_1 = require("apollo-server-env");
14const graphqlOptions_1 = require("./graphqlOptions");
15const apollo_server_errors_1 = require("apollo-server-errors");
16const requestPipeline_1 = require("./requestPipeline");
17class HttpQueryError extends Error {
18 constructor(statusCode, message, isGraphQLError = false, headers) {
19 super(message);
20 this.name = 'HttpQueryError';
21 this.statusCode = statusCode;
22 this.isGraphQLError = isGraphQLError;
23 this.headers = headers;
24 }
25}
26exports.HttpQueryError = HttpQueryError;
27function throwHttpGraphQLError(statusCode, errors, options, extensions) {
28 const defaultHeaders = { 'Content-Type': 'application/json' };
29 const headers = apollo_server_errors_1.hasPersistedQueryError(errors)
30 ? Object.assign(Object.assign({}, defaultHeaders), { 'Cache-Control': 'private, no-cache, must-revalidate' }) : defaultHeaders;
31 const result = {
32 errors: options
33 ? apollo_server_errors_1.formatApolloErrors(errors, {
34 debug: options.debug,
35 formatter: options.formatError,
36 })
37 : errors,
38 };
39 if (extensions) {
40 result.extensions = extensions;
41 }
42 throw new HttpQueryError(statusCode, prettyJSONStringify(result), true, headers);
43}
44exports.throwHttpGraphQLError = throwHttpGraphQLError;
45function runHttpQuery(handlerArguments, request) {
46 return __awaiter(this, void 0, void 0, function* () {
47 let options;
48 const debugDefault = process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test';
49 try {
50 options = yield graphqlOptions_1.resolveGraphqlOptions(request.options, ...handlerArguments);
51 }
52 catch (e) {
53 return throwHttpGraphQLError(500, [e], { debug: debugDefault });
54 }
55 if (options.debug === undefined) {
56 options.debug = debugDefault;
57 }
58 if (typeof options.context === 'function') {
59 try {
60 options.context();
61 }
62 catch (e) {
63 e.message = `Context creation failed: ${e.message}`;
64 if (e.extensions &&
65 e.extensions.code &&
66 e.extensions.code !== 'INTERNAL_SERVER_ERROR') {
67 return throwHttpGraphQLError(400, [e], options);
68 }
69 else {
70 return throwHttpGraphQLError(500, [e], options);
71 }
72 }
73 }
74 const config = {
75 schema: options.schema,
76 schemaHash: options.schemaHash,
77 logger: options.logger,
78 rootValue: options.rootValue,
79 context: options.context || {},
80 validationRules: options.validationRules,
81 executor: options.executor,
82 fieldResolver: options.fieldResolver,
83 cache: options.cache,
84 dataSources: options.dataSources,
85 documentStore: options.documentStore,
86 extensions: options.extensions,
87 persistedQueries: options.persistedQueries,
88 tracing: options.tracing,
89 formatError: options.formatError,
90 formatResponse: options.formatResponse,
91 debug: options.debug,
92 plugins: options.plugins || [],
93 };
94 return processHTTPRequest(config, request);
95 });
96}
97exports.runHttpQuery = runHttpQuery;
98function processHTTPRequest(options, httpRequest) {
99 return __awaiter(this, void 0, void 0, function* () {
100 let requestPayload;
101 switch (httpRequest.method) {
102 case 'POST':
103 if (!httpRequest.query || Object.keys(httpRequest.query).length === 0) {
104 throw new HttpQueryError(500, 'POST body missing. Did you forget use body-parser middleware?');
105 }
106 requestPayload = httpRequest.query;
107 break;
108 case 'GET':
109 if (!httpRequest.query || Object.keys(httpRequest.query).length === 0) {
110 throw new HttpQueryError(400, 'GET query missing.');
111 }
112 requestPayload = httpRequest.query;
113 break;
114 default:
115 throw new HttpQueryError(405, 'Apollo Server supports only GET/POST requests.', false, {
116 Allow: 'GET, POST',
117 });
118 }
119 options = Object.assign(Object.assign({}, options), { plugins: [checkOperationPlugin, ...options.plugins] });
120 function buildRequestContext(request) {
121 const context = cloneObject(options.context);
122 return {
123 logger: options.logger || console,
124 schema: options.schema,
125 schemaHash: options.schemaHash,
126 request,
127 response: {
128 http: {
129 headers: new apollo_server_env_1.Headers(),
130 },
131 },
132 context,
133 cache: options.cache,
134 debug: options.debug,
135 metrics: {},
136 };
137 }
138 const responseInit = {
139 headers: {
140 'Content-Type': 'application/json',
141 },
142 };
143 let body;
144 try {
145 if (Array.isArray(requestPayload)) {
146 const requests = requestPayload.map(requestParams => parseGraphQLRequest(httpRequest.request, requestParams));
147 const responses = yield Promise.all(requests.map((request) => __awaiter(this, void 0, void 0, function* () {
148 try {
149 const requestContext = buildRequestContext(request);
150 return yield requestPipeline_1.processGraphQLRequest(options, requestContext);
151 }
152 catch (error) {
153 return {
154 errors: apollo_server_errors_1.formatApolloErrors([error], options),
155 };
156 }
157 })));
158 body = prettyJSONStringify(responses.map(serializeGraphQLResponse));
159 }
160 else {
161 const request = parseGraphQLRequest(httpRequest.request, requestPayload);
162 try {
163 const requestContext = buildRequestContext(request);
164 const response = yield requestPipeline_1.processGraphQLRequest(options, requestContext);
165 if (response.errors && typeof response.data === 'undefined') {
166 return throwHttpGraphQLError((response.http && response.http.status) || 400, response.errors, undefined, response.extensions);
167 }
168 if (response.http) {
169 for (const [name, value] of response.http.headers) {
170 responseInit.headers[name] = value;
171 }
172 }
173 body = prettyJSONStringify(serializeGraphQLResponse(response));
174 }
175 catch (error) {
176 if (error instanceof requestPipeline_1.InvalidGraphQLRequestError) {
177 throw new HttpQueryError(400, error.message);
178 }
179 else if (error instanceof apollo_server_errors_1.PersistedQueryNotSupportedError ||
180 error instanceof apollo_server_errors_1.PersistedQueryNotFoundError) {
181 return throwHttpGraphQLError(200, [error], options);
182 }
183 else {
184 throw error;
185 }
186 }
187 }
188 }
189 catch (error) {
190 if (error instanceof HttpQueryError) {
191 throw error;
192 }
193 return throwHttpGraphQLError(500, [error], options);
194 }
195 responseInit.headers['Content-Length'] = Buffer.byteLength(body, 'utf8').toString();
196 return {
197 graphqlResponse: body,
198 responseInit,
199 };
200 });
201}
202exports.processHTTPRequest = processHTTPRequest;
203function parseGraphQLRequest(httpRequest, requestParams) {
204 let queryString = requestParams.query;
205 let extensions = requestParams.extensions;
206 if (typeof extensions === 'string' && extensions !== '') {
207 try {
208 extensions = JSON.parse(extensions);
209 }
210 catch (error) {
211 throw new HttpQueryError(400, 'Extensions are invalid JSON.');
212 }
213 }
214 if (queryString && typeof queryString !== 'string') {
215 if (queryString.kind === 'Document') {
216 throw new HttpQueryError(400, "GraphQL queries must be strings. It looks like you're sending the " +
217 'internal graphql-js representation of a parsed query in your ' +
218 'request instead of a request in the GraphQL query language. You ' +
219 'can convert an AST to a string using the `print` function from ' +
220 '`graphql`, or use a client like `apollo-client` which converts ' +
221 'the internal representation to a string for you.');
222 }
223 else {
224 throw new HttpQueryError(400, 'GraphQL queries must be strings.');
225 }
226 }
227 const operationName = requestParams.operationName;
228 let variables = requestParams.variables;
229 if (typeof variables === 'string' && variables !== '') {
230 try {
231 variables = JSON.parse(variables);
232 }
233 catch (error) {
234 throw new HttpQueryError(400, 'Variables are invalid JSON.');
235 }
236 }
237 return {
238 query: queryString,
239 operationName,
240 variables,
241 extensions,
242 http: httpRequest,
243 };
244}
245const checkOperationPlugin = {
246 requestDidStart() {
247 return {
248 didResolveOperation({ request, operation }) {
249 if (!request.http)
250 return;
251 if (request.http.method === 'GET' && operation.operation !== 'query') {
252 throw new HttpQueryError(405, `GET supports only query operation`, false, {
253 Allow: 'POST',
254 });
255 }
256 },
257 };
258 },
259};
260function serializeGraphQLResponse(response) {
261 return {
262 errors: response.errors,
263 data: response.data,
264 extensions: response.extensions,
265 };
266}
267function prettyJSONStringify(value) {
268 return JSON.stringify(value) + '\n';
269}
270function cloneObject(object) {
271 return Object.assign(Object.create(Object.getPrototypeOf(object)), object);
272}
273exports.cloneObject = cloneObject;
274//# sourceMappingURL=runHttpQuery.js.map
\No newline at end of file