123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- "use strict";
- var __importDefault = (this && this.__importDefault) || function (mod) {
- return (mod && mod.__esModule) ? mod : { "default": mod };
- };
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.mergeHTTPGraphQLHead = exports.newHTTPGraphQLHead = exports.prettyJSONStringify = exports.runHttpQuery = void 0;
- const ApolloServer_js_1 = require("./ApolloServer.js");
- const graphql_1 = require("graphql");
- const internalErrorClasses_js_1 = require("./internalErrorClasses.js");
- const negotiator_1 = __importDefault(require("negotiator"));
- const HeaderMap_js_1 = require("./utils/HeaderMap.js");
- function fieldIfString(o, fieldName) {
- const value = o[fieldName];
- if (typeof value === 'string') {
- return value;
- }
- return undefined;
- }
- function searchParamIfSpecifiedOnce(searchParams, paramName) {
- const values = searchParams.getAll(paramName);
- switch (values.length) {
- case 0:
- return undefined;
- case 1:
- return values[0];
- default:
- throw new internalErrorClasses_js_1.BadRequestError(`The '${paramName}' search parameter may only be specified once.`);
- }
- }
- function jsonParsedSearchParamIfSpecifiedOnce(searchParams, fieldName) {
- const value = searchParamIfSpecifiedOnce(searchParams, fieldName);
- if (value === undefined) {
- return undefined;
- }
- let hopefullyRecord;
- try {
- hopefullyRecord = JSON.parse(value);
- }
- catch {
- throw new internalErrorClasses_js_1.BadRequestError(`The ${fieldName} search parameter contains invalid JSON.`);
- }
- if (!isStringRecord(hopefullyRecord)) {
- throw new internalErrorClasses_js_1.BadRequestError(`The ${fieldName} search parameter should contain a JSON-encoded object.`);
- }
- return hopefullyRecord;
- }
- function fieldIfRecord(o, fieldName) {
- const value = o[fieldName];
- if (isStringRecord(value)) {
- return value;
- }
- return undefined;
- }
- function isStringRecord(o) {
- return (!!o && typeof o === 'object' && !Buffer.isBuffer(o) && !Array.isArray(o));
- }
- function isNonEmptyStringRecord(o) {
- return isStringRecord(o) && Object.keys(o).length > 0;
- }
- function ensureQueryIsStringOrMissing(query) {
- if (!query || typeof query === 'string') {
- return;
- }
- if (query.kind === graphql_1.Kind.DOCUMENT) {
- throw new internalErrorClasses_js_1.BadRequestError("GraphQL queries must be strings. It looks like you're sending the " +
- 'internal graphql-js representation of a parsed query in your ' +
- 'request instead of a request in the GraphQL query language. You ' +
- 'can convert an AST to a string using the `print` function from ' +
- '`graphql`, or use a client like `apollo-client` which converts ' +
- 'the internal representation to a string for you.');
- }
- else {
- throw new internalErrorClasses_js_1.BadRequestError('GraphQL queries must be strings.');
- }
- }
- async function runHttpQuery({ server, httpRequest, contextValue, schemaDerivedData, internals, sharedResponseHTTPGraphQLHead, }) {
- let graphQLRequest;
- switch (httpRequest.method) {
- case 'POST': {
- if (!isNonEmptyStringRecord(httpRequest.body)) {
- throw new internalErrorClasses_js_1.BadRequestError('POST body missing, invalid Content-Type, or JSON object has no keys.');
- }
- ensureQueryIsStringOrMissing(httpRequest.body.query);
- if (typeof httpRequest.body.variables === 'string') {
- throw new internalErrorClasses_js_1.BadRequestError('`variables` in a POST body should be provided as an object, not a recursively JSON-encoded string.');
- }
- if (typeof httpRequest.body.extensions === 'string') {
- throw new internalErrorClasses_js_1.BadRequestError('`extensions` in a POST body should be provided as an object, not a recursively JSON-encoded string.');
- }
- if ('extensions' in httpRequest.body &&
- httpRequest.body.extensions !== null &&
- !isStringRecord(httpRequest.body.extensions)) {
- throw new internalErrorClasses_js_1.BadRequestError('`extensions` in a POST body must be an object if provided.');
- }
- if ('variables' in httpRequest.body &&
- httpRequest.body.variables !== null &&
- !isStringRecord(httpRequest.body.variables)) {
- throw new internalErrorClasses_js_1.BadRequestError('`variables` in a POST body must be an object if provided.');
- }
- if ('operationName' in httpRequest.body &&
- httpRequest.body.operationName !== null &&
- typeof httpRequest.body.operationName !== 'string') {
- throw new internalErrorClasses_js_1.BadRequestError('`operationName` in a POST body must be a string if provided.');
- }
- graphQLRequest = {
- query: fieldIfString(httpRequest.body, 'query'),
- operationName: fieldIfString(httpRequest.body, 'operationName'),
- variables: fieldIfRecord(httpRequest.body, 'variables'),
- extensions: fieldIfRecord(httpRequest.body, 'extensions'),
- http: httpRequest,
- };
- break;
- }
- case 'GET': {
- const searchParams = new URLSearchParams(httpRequest.search);
- graphQLRequest = {
- query: searchParamIfSpecifiedOnce(searchParams, 'query'),
- operationName: searchParamIfSpecifiedOnce(searchParams, 'operationName'),
- variables: jsonParsedSearchParamIfSpecifiedOnce(searchParams, 'variables'),
- extensions: jsonParsedSearchParamIfSpecifiedOnce(searchParams, 'extensions'),
- http: httpRequest,
- };
- break;
- }
- default:
- throw new internalErrorClasses_js_1.BadRequestError('Apollo Server supports only GET/POST requests.', {
- extensions: {
- http: {
- status: 405,
- headers: new HeaderMap_js_1.HeaderMap([['allow', 'GET, POST']]),
- },
- },
- });
- }
- const graphQLResponse = await (0, ApolloServer_js_1.internalExecuteOperation)({
- server,
- graphQLRequest,
- internals,
- schemaDerivedData,
- sharedResponseHTTPGraphQLHead,
- }, { contextValue });
- if (graphQLResponse.body.kind === 'single') {
- if (!graphQLResponse.http.headers.get('content-type')) {
- const contentType = (0, ApolloServer_js_1.chooseContentTypeForSingleResultResponse)(httpRequest);
- if (contentType === null) {
- throw new internalErrorClasses_js_1.BadRequestError(`An 'accept' header was provided for this request which does not accept ` +
- `${ApolloServer_js_1.MEDIA_TYPES.APPLICATION_JSON} or ${ApolloServer_js_1.MEDIA_TYPES.APPLICATION_GRAPHQL_RESPONSE_JSON}`, { extensions: { http: { status: 406 } } });
- }
- graphQLResponse.http.headers.set('content-type', contentType);
- }
- return {
- ...graphQLResponse.http,
- body: {
- kind: 'complete',
- string: await internals.stringifyResult(orderExecutionResultFields(graphQLResponse.body.singleResult)),
- },
- };
- }
- const acceptHeader = httpRequest.headers.get('accept');
- if (!(acceptHeader &&
- new negotiator_1.default({
- headers: { accept: httpRequest.headers.get('accept') },
- }).mediaType([
- ApolloServer_js_1.MEDIA_TYPES.MULTIPART_MIXED_NO_DEFER_SPEC,
- ApolloServer_js_1.MEDIA_TYPES.MULTIPART_MIXED_EXPERIMENTAL,
- ]) === ApolloServer_js_1.MEDIA_TYPES.MULTIPART_MIXED_EXPERIMENTAL)) {
- throw new internalErrorClasses_js_1.BadRequestError('Apollo server received an operation that uses incremental delivery ' +
- '(@defer or @stream), but the client does not accept multipart/mixed ' +
- 'HTTP responses. To enable incremental delivery support, add the HTTP ' +
- "header 'Accept: multipart/mixed; deferSpec=20220824'.", { extensions: { http: { status: 406 } } });
- }
- graphQLResponse.http.headers.set('content-type', 'multipart/mixed; boundary="-"; deferSpec=20220824');
- return {
- ...graphQLResponse.http,
- body: {
- kind: 'chunked',
- asyncIterator: writeMultipartBody(graphQLResponse.body.initialResult, graphQLResponse.body.subsequentResults),
- },
- };
- }
- exports.runHttpQuery = runHttpQuery;
- async function* writeMultipartBody(initialResult, subsequentResults) {
- yield `\r\n---\r\ncontent-type: application/json; charset=utf-8\r\n\r\n${JSON.stringify(orderInitialIncrementalExecutionResultFields(initialResult))}\r\n---${initialResult.hasNext ? '' : '--'}\r\n`;
- for await (const result of subsequentResults) {
- yield `content-type: application/json; charset=utf-8\r\n\r\n${JSON.stringify(orderSubsequentIncrementalExecutionResultFields(result))}\r\n---${result.hasNext ? '' : '--'}\r\n`;
- }
- }
- function orderExecutionResultFields(result) {
- return {
- errors: result.errors,
- data: result.data,
- extensions: result.extensions,
- };
- }
- function orderInitialIncrementalExecutionResultFields(result) {
- return {
- hasNext: result.hasNext,
- errors: result.errors,
- data: result.data,
- incremental: orderIncrementalResultFields(result.incremental),
- extensions: result.extensions,
- };
- }
- function orderSubsequentIncrementalExecutionResultFields(result) {
- return {
- hasNext: result.hasNext,
- incremental: orderIncrementalResultFields(result.incremental),
- extensions: result.extensions,
- };
- }
- function orderIncrementalResultFields(incremental) {
- return incremental?.map((i) => ({
- hasNext: i.hasNext,
- errors: i.errors,
- path: i.path,
- label: i.label,
- data: i.data,
- items: i.items,
- extensions: i.extensions,
- }));
- }
- function prettyJSONStringify(value) {
- return JSON.stringify(value) + '\n';
- }
- exports.prettyJSONStringify = prettyJSONStringify;
- function newHTTPGraphQLHead(status) {
- return {
- status,
- headers: new HeaderMap_js_1.HeaderMap(),
- };
- }
- exports.newHTTPGraphQLHead = newHTTPGraphQLHead;
- function mergeHTTPGraphQLHead(target, source) {
- if (source.status) {
- target.status = source.status;
- }
- if (source.headers) {
- for (const [name, value] of source.headers) {
- target.headers.set(name, value);
- }
- }
- }
- exports.mergeHTTPGraphQLHead = mergeHTTPGraphQLHead;
- //# sourceMappingURL=runHttpQuery.js.map
|