ApolloServer.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. "use strict";
  2. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
  3. if (k2 === undefined) k2 = k;
  4. var desc = Object.getOwnPropertyDescriptor(m, k);
  5. if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
  6. desc = { enumerable: true, get: function() { return m[k]; } };
  7. }
  8. Object.defineProperty(o, k2, desc);
  9. }) : (function(o, m, k, k2) {
  10. if (k2 === undefined) k2 = k;
  11. o[k2] = m[k];
  12. }));
  13. var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
  14. Object.defineProperty(o, "default", { enumerable: true, value: v });
  15. }) : function(o, v) {
  16. o["default"] = v;
  17. });
  18. var __importStar = (this && this.__importStar) || function (mod) {
  19. if (mod && mod.__esModule) return mod;
  20. var result = {};
  21. if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
  22. __setModuleDefault(result, mod);
  23. return result;
  24. };
  25. var __importDefault = (this && this.__importDefault) || function (mod) {
  26. return (mod && mod.__esModule) ? mod : { "default": mod };
  27. };
  28. Object.defineProperty(exports, "__esModule", { value: true });
  29. exports.chooseContentTypeForSingleResultResponse = exports.MEDIA_TYPES = exports.isImplicitlyInstallablePlugin = exports.internalExecuteOperation = exports.ApolloServer = void 0;
  30. const utils_isnodelike_1 = require("@apollo/utils.isnodelike");
  31. const utils_keyvaluecache_1 = require("@apollo/utils.keyvaluecache");
  32. const schema_1 = require("@graphql-tools/schema");
  33. const resolvable_js_1 = __importDefault(require("./utils/resolvable.js"));
  34. const graphql_1 = require("graphql");
  35. const loglevel_1 = __importDefault(require("loglevel"));
  36. const negotiator_1 = __importDefault(require("negotiator"));
  37. const cachePolicy_js_1 = require("./cachePolicy.js");
  38. const determineApolloConfig_js_1 = require("./determineApolloConfig.js");
  39. const errorNormalize_js_1 = require("./errorNormalize.js");
  40. const index_js_1 = require("./errors/index.js");
  41. const httpBatching_js_1 = require("./httpBatching.js");
  42. const internalPlugin_js_1 = require("./internalPlugin.js");
  43. const preventCsrf_js_1 = require("./preventCsrf.js");
  44. const requestPipeline_js_1 = require("./requestPipeline.js");
  45. const runHttpQuery_js_1 = require("./runHttpQuery.js");
  46. const HeaderMap_js_1 = require("./utils/HeaderMap.js");
  47. const UnreachableCaseError_js_1 = require("./utils/UnreachableCaseError.js");
  48. const computeCoreSchemaHash_js_1 = require("./utils/computeCoreSchemaHash.js");
  49. const isDefined_js_1 = require("./utils/isDefined.js");
  50. const schemaManager_js_1 = require("./utils/schemaManager.js");
  51. const NoIntrospection = (context) => ({
  52. Field(node) {
  53. if (node.name.value === '__schema' || node.name.value === '__type') {
  54. context.reportError(new graphql_1.GraphQLError('GraphQL introspection is not allowed by Apollo Server, but the query contained __schema or __type. To enable introspection, pass introspection: true to ApolloServer in production', {
  55. nodes: [node],
  56. extensions: {
  57. validationErrorCode: index_js_1.ApolloServerValidationErrorCode.INTROSPECTION_DISABLED,
  58. },
  59. }));
  60. }
  61. },
  62. });
  63. function defaultLogger() {
  64. const loglevelLogger = loglevel_1.default.getLogger('apollo-server');
  65. loglevelLogger.setLevel(loglevel_1.default.levels.INFO);
  66. return loglevelLogger;
  67. }
  68. class ApolloServer {
  69. constructor(config) {
  70. const nodeEnv = config.nodeEnv ?? process.env.NODE_ENV ?? '';
  71. this.logger = config.logger ?? defaultLogger();
  72. const apolloConfig = (0, determineApolloConfig_js_1.determineApolloConfig)(config.apollo, this.logger);
  73. const isDev = nodeEnv !== 'production';
  74. if (config.cache &&
  75. config.cache !== 'bounded' &&
  76. utils_keyvaluecache_1.PrefixingKeyValueCache.prefixesAreUnnecessaryForIsolation(config.cache)) {
  77. throw new Error('You cannot pass a cache returned from ' +
  78. '`PrefixingKeyValueCache.cacheDangerouslyDoesNotNeedPrefixesForIsolation`' +
  79. 'to `new ApolloServer({ cache })`, because Apollo Server may use it for ' +
  80. 'multiple features whose cache keys must be distinct from each other.');
  81. }
  82. const state = config.gateway
  83. ?
  84. {
  85. phase: 'initialized',
  86. schemaManager: new schemaManager_js_1.SchemaManager({
  87. gateway: config.gateway,
  88. apolloConfig,
  89. schemaDerivedDataProvider: (schema) => ApolloServer.generateSchemaDerivedData(schema, config.documentStore),
  90. logger: this.logger,
  91. }),
  92. }
  93. :
  94. {
  95. phase: 'initialized',
  96. schemaManager: new schemaManager_js_1.SchemaManager({
  97. apiSchema: ApolloServer.constructSchema(config),
  98. schemaDerivedDataProvider: (schema) => ApolloServer.generateSchemaDerivedData(schema, config.documentStore),
  99. logger: this.logger,
  100. }),
  101. };
  102. const introspectionEnabled = config.introspection ?? isDev;
  103. this.cache =
  104. config.cache === undefined || config.cache === 'bounded'
  105. ? new utils_keyvaluecache_1.InMemoryLRUCache()
  106. : config.cache;
  107. this.internals = {
  108. formatError: config.formatError,
  109. rootValue: config.rootValue,
  110. validationRules: [
  111. ...(config.validationRules ?? []),
  112. ...(introspectionEnabled ? [] : [NoIntrospection]),
  113. ],
  114. dangerouslyDisableValidation: config.dangerouslyDisableValidation ?? false,
  115. fieldResolver: config.fieldResolver,
  116. includeStacktraceInErrorResponses: config.includeStacktraceInErrorResponses ??
  117. (nodeEnv !== 'production' && nodeEnv !== 'test'),
  118. persistedQueries: config.persistedQueries === false
  119. ? undefined
  120. : {
  121. ...config.persistedQueries,
  122. cache: new utils_keyvaluecache_1.PrefixingKeyValueCache(config.persistedQueries?.cache ?? this.cache, requestPipeline_js_1.APQ_CACHE_PREFIX),
  123. },
  124. nodeEnv,
  125. allowBatchedHttpRequests: config.allowBatchedHttpRequests ?? false,
  126. apolloConfig,
  127. plugins: config.plugins ?? [],
  128. parseOptions: config.parseOptions ?? {},
  129. state,
  130. stopOnTerminationSignals: config.stopOnTerminationSignals,
  131. gatewayExecutor: null,
  132. csrfPreventionRequestHeaders: config.csrfPrevention === true || config.csrfPrevention === undefined
  133. ? preventCsrf_js_1.recommendedCsrfPreventionRequestHeaders
  134. : config.csrfPrevention === false
  135. ? null
  136. : (config.csrfPrevention.requestHeaders ??
  137. preventCsrf_js_1.recommendedCsrfPreventionRequestHeaders),
  138. status400ForVariableCoercionErrors: config.status400ForVariableCoercionErrors ?? false,
  139. __testing_incrementalExecutionResults: config.__testing_incrementalExecutionResults,
  140. stringifyResult: config.stringifyResult ?? runHttpQuery_js_1.prettyJSONStringify,
  141. };
  142. }
  143. async start() {
  144. return await this._start(false);
  145. }
  146. startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests() {
  147. this._start(true).catch((e) => this.logStartupError(e));
  148. }
  149. async _start(startedInBackground) {
  150. if (this.internals.state.phase !== 'initialized') {
  151. throw new Error(`You should only call 'start()' or ` +
  152. `'startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests()' ` +
  153. `once on your ApolloServer.`);
  154. }
  155. const schemaManager = this.internals.state.schemaManager;
  156. const barrier = (0, resolvable_js_1.default)();
  157. this.internals.state = {
  158. phase: 'starting',
  159. barrier,
  160. schemaManager,
  161. startedInBackground,
  162. };
  163. try {
  164. await this.addDefaultPlugins();
  165. const toDispose = [];
  166. const executor = await schemaManager.start();
  167. if (executor) {
  168. this.internals.gatewayExecutor = executor;
  169. }
  170. toDispose.push(async () => {
  171. await schemaManager.stop();
  172. });
  173. const schemaDerivedData = schemaManager.getSchemaDerivedData();
  174. const service = {
  175. logger: this.logger,
  176. cache: this.cache,
  177. schema: schemaDerivedData.schema,
  178. apollo: this.internals.apolloConfig,
  179. startedInBackground,
  180. };
  181. const taggedServerListeners = (await Promise.all(this.internals.plugins.map(async (plugin) => ({
  182. serverListener: plugin.serverWillStart && (await plugin.serverWillStart(service)),
  183. installedImplicitly: isImplicitlyInstallablePlugin(plugin) &&
  184. plugin.__internal_installed_implicitly__,
  185. })))).filter((maybeTaggedServerListener) => typeof maybeTaggedServerListener.serverListener === 'object');
  186. taggedServerListeners.forEach(({ serverListener: { schemaDidLoadOrUpdate } }) => {
  187. if (schemaDidLoadOrUpdate) {
  188. schemaManager.onSchemaLoadOrUpdate(schemaDidLoadOrUpdate);
  189. }
  190. });
  191. const serverWillStops = taggedServerListeners
  192. .map((l) => l.serverListener.serverWillStop)
  193. .filter(isDefined_js_1.isDefined);
  194. if (serverWillStops.length) {
  195. toDispose.push(async () => {
  196. await Promise.all(serverWillStops.map((serverWillStop) => serverWillStop()));
  197. });
  198. }
  199. const drainServerCallbacks = taggedServerListeners
  200. .map((l) => l.serverListener.drainServer)
  201. .filter(isDefined_js_1.isDefined);
  202. const drainServers = drainServerCallbacks.length
  203. ? async () => {
  204. await Promise.all(drainServerCallbacks.map((drainServer) => drainServer()));
  205. }
  206. : null;
  207. let taggedServerListenersWithRenderLandingPage = taggedServerListeners.filter((l) => l.serverListener.renderLandingPage);
  208. if (taggedServerListenersWithRenderLandingPage.length > 1) {
  209. taggedServerListenersWithRenderLandingPage =
  210. taggedServerListenersWithRenderLandingPage.filter((l) => !l.installedImplicitly);
  211. }
  212. let landingPage = null;
  213. if (taggedServerListenersWithRenderLandingPage.length > 1) {
  214. throw Error('Only one plugin can implement renderLandingPage.');
  215. }
  216. else if (taggedServerListenersWithRenderLandingPage.length) {
  217. landingPage =
  218. await taggedServerListenersWithRenderLandingPage[0].serverListener
  219. .renderLandingPage();
  220. }
  221. const toDisposeLast = this.maybeRegisterTerminationSignalHandlers(['SIGINT', 'SIGTERM'], startedInBackground);
  222. this.internals.state = {
  223. phase: 'started',
  224. schemaManager,
  225. drainServers,
  226. landingPage,
  227. toDispose,
  228. toDisposeLast,
  229. };
  230. }
  231. catch (maybeError) {
  232. const error = (0, errorNormalize_js_1.ensureError)(maybeError);
  233. try {
  234. await Promise.all(this.internals.plugins.map(async (plugin) => plugin.startupDidFail?.({ error })));
  235. }
  236. catch (pluginError) {
  237. this.logger.error(`startupDidFail hook threw: ${pluginError}`);
  238. }
  239. this.internals.state = {
  240. phase: 'failed to start',
  241. error,
  242. };
  243. throw error;
  244. }
  245. finally {
  246. barrier.resolve();
  247. }
  248. }
  249. maybeRegisterTerminationSignalHandlers(signals, startedInBackground) {
  250. const toDisposeLast = [];
  251. if (this.internals.stopOnTerminationSignals === false ||
  252. (this.internals.stopOnTerminationSignals === undefined &&
  253. !(utils_isnodelike_1.isNodeLike &&
  254. this.internals.nodeEnv !== 'test' &&
  255. !startedInBackground))) {
  256. return toDisposeLast;
  257. }
  258. let receivedSignal = false;
  259. const signalHandler = async (signal) => {
  260. if (receivedSignal) {
  261. return;
  262. }
  263. receivedSignal = true;
  264. try {
  265. await this.stop();
  266. }
  267. catch (e) {
  268. this.logger.error(`stop() threw during ${signal} shutdown`);
  269. this.logger.error(e);
  270. process.exit(1);
  271. }
  272. process.kill(process.pid, signal);
  273. };
  274. signals.forEach((signal) => {
  275. process.on(signal, signalHandler);
  276. toDisposeLast.push(async () => {
  277. process.removeListener(signal, signalHandler);
  278. });
  279. });
  280. return toDisposeLast;
  281. }
  282. async _ensureStarted() {
  283. while (true) {
  284. switch (this.internals.state.phase) {
  285. case 'initialized':
  286. throw new Error('You need to call `server.start()` before using your Apollo Server.');
  287. case 'starting':
  288. await this.internals.state.barrier;
  289. break;
  290. case 'failed to start':
  291. this.logStartupError(this.internals.state.error);
  292. throw new Error('This data graph is missing a valid configuration. More details may be available in the server logs.');
  293. case 'started':
  294. case 'draining':
  295. return this.internals.state;
  296. case 'stopping':
  297. case 'stopped':
  298. this.logger.warn('A GraphQL operation was received during server shutdown. The ' +
  299. 'operation will fail. Consider draining the HTTP server on shutdown; ' +
  300. 'see https://go.apollo.dev/s/drain for details.');
  301. throw new Error(`Cannot execute GraphQL operations ${this.internals.state.phase === 'stopping'
  302. ? 'while the server is stopping'
  303. : 'after the server has stopped'}.'`);
  304. default:
  305. throw new UnreachableCaseError_js_1.UnreachableCaseError(this.internals.state);
  306. }
  307. }
  308. }
  309. assertStarted(expressionForError) {
  310. if (this.internals.state.phase !== 'started' &&
  311. this.internals.state.phase !== 'draining' &&
  312. !(this.internals.state.phase === 'starting' &&
  313. this.internals.state.startedInBackground)) {
  314. throw new Error('You must `await server.start()` before calling `' +
  315. expressionForError +
  316. '`');
  317. }
  318. }
  319. logStartupError(err) {
  320. this.logger.error('An error occurred during Apollo Server startup. All GraphQL requests ' +
  321. 'will now fail. The startup error was: ' +
  322. (err?.message || err));
  323. }
  324. static constructSchema(config) {
  325. if (config.schema) {
  326. return config.schema;
  327. }
  328. const { typeDefs, resolvers } = config;
  329. const augmentedTypeDefs = Array.isArray(typeDefs) ? typeDefs : [typeDefs];
  330. return (0, schema_1.makeExecutableSchema)({
  331. typeDefs: augmentedTypeDefs,
  332. resolvers,
  333. });
  334. }
  335. static generateSchemaDerivedData(schema, providedDocumentStore) {
  336. (0, graphql_1.assertValidSchema)(schema);
  337. return {
  338. schema,
  339. documentStore: providedDocumentStore === undefined
  340. ? new utils_keyvaluecache_1.InMemoryLRUCache()
  341. : providedDocumentStore,
  342. documentStoreKeyPrefix: providedDocumentStore
  343. ? `${(0, computeCoreSchemaHash_js_1.computeCoreSchemaHash)((0, graphql_1.printSchema)(schema))}:`
  344. : '',
  345. };
  346. }
  347. async stop() {
  348. switch (this.internals.state.phase) {
  349. case 'initialized':
  350. case 'starting':
  351. case 'failed to start':
  352. throw Error('apolloServer.stop() should only be called after `await apolloServer.start()` has succeeded');
  353. case 'stopped':
  354. if (this.internals.state.stopError) {
  355. throw this.internals.state.stopError;
  356. }
  357. return;
  358. case 'stopping':
  359. case 'draining': {
  360. await this.internals.state.barrier;
  361. const state = this.internals.state;
  362. if (state.phase !== 'stopped') {
  363. throw Error(`Surprising post-stopping state ${state.phase}`);
  364. }
  365. if (state.stopError) {
  366. throw state.stopError;
  367. }
  368. return;
  369. }
  370. case 'started':
  371. break;
  372. default:
  373. throw new UnreachableCaseError_js_1.UnreachableCaseError(this.internals.state);
  374. }
  375. const barrier = (0, resolvable_js_1.default)();
  376. const { schemaManager, drainServers, landingPage, toDispose, toDisposeLast, } = this.internals.state;
  377. this.internals.state = {
  378. phase: 'draining',
  379. barrier,
  380. schemaManager,
  381. landingPage,
  382. };
  383. try {
  384. await drainServers?.();
  385. this.internals.state = { phase: 'stopping', barrier };
  386. await Promise.all([...toDispose].map((dispose) => dispose()));
  387. await Promise.all([...toDisposeLast].map((dispose) => dispose()));
  388. }
  389. catch (stopError) {
  390. this.internals.state = {
  391. phase: 'stopped',
  392. stopError: stopError,
  393. };
  394. barrier.resolve();
  395. throw stopError;
  396. }
  397. this.internals.state = { phase: 'stopped', stopError: null };
  398. }
  399. async addDefaultPlugins() {
  400. const { plugins, apolloConfig, nodeEnv } = this.internals;
  401. const isDev = nodeEnv !== 'production';
  402. const alreadyHavePluginWithInternalId = (id) => plugins.some((p) => (0, internalPlugin_js_1.pluginIsInternal)(p) && p.__internal_plugin_id__ === id);
  403. const pluginsByInternalID = new Map();
  404. for (const p of plugins) {
  405. if ((0, internalPlugin_js_1.pluginIsInternal)(p)) {
  406. const id = p.__internal_plugin_id__;
  407. if (!pluginsByInternalID.has(id)) {
  408. pluginsByInternalID.set(id, {
  409. sawDisabled: false,
  410. sawNonDisabled: false,
  411. });
  412. }
  413. const seen = pluginsByInternalID.get(id);
  414. if (p.__is_disabled_plugin__) {
  415. seen.sawDisabled = true;
  416. }
  417. else {
  418. seen.sawNonDisabled = true;
  419. }
  420. if (seen.sawDisabled && seen.sawNonDisabled) {
  421. throw new Error(`You have tried to install both ApolloServerPlugin${id} and ` +
  422. `ApolloServerPlugin${id}Disabled in your server. Please choose ` +
  423. `whether or not you want to disable the feature and install the ` +
  424. `appropriate plugin for your use case.`);
  425. }
  426. }
  427. }
  428. {
  429. if (!alreadyHavePluginWithInternalId('CacheControl')) {
  430. const { ApolloServerPluginCacheControl } = await Promise.resolve().then(() => __importStar(require('./plugin/cacheControl/index.js')));
  431. plugins.push(ApolloServerPluginCacheControl());
  432. }
  433. }
  434. {
  435. const alreadyHavePlugin = alreadyHavePluginWithInternalId('UsageReporting');
  436. if (!alreadyHavePlugin && apolloConfig.key) {
  437. if (apolloConfig.graphRef) {
  438. const { ApolloServerPluginUsageReporting } = await Promise.resolve().then(() => __importStar(require('./plugin/usageReporting/index.js')));
  439. plugins.unshift(ApolloServerPluginUsageReporting({
  440. __onlyIfSchemaIsNotSubgraph: true,
  441. }));
  442. }
  443. else {
  444. this.logger.warn('You have specified an Apollo key but have not specified a graph ref; usage ' +
  445. 'reporting is disabled. To enable usage reporting, set the `APOLLO_GRAPH_REF` ' +
  446. 'environment variable to `your-graph-id@your-graph-variant`. To disable this ' +
  447. 'warning, install `ApolloServerPluginUsageReportingDisabled`.');
  448. }
  449. }
  450. }
  451. {
  452. const alreadyHavePlugin = alreadyHavePluginWithInternalId('SchemaReporting');
  453. const enabledViaEnvVar = process.env.APOLLO_SCHEMA_REPORTING === 'true';
  454. if (!alreadyHavePlugin && enabledViaEnvVar) {
  455. if (apolloConfig.key) {
  456. const { ApolloServerPluginSchemaReporting } = await Promise.resolve().then(() => __importStar(require('./plugin/schemaReporting/index.js')));
  457. plugins.push(ApolloServerPluginSchemaReporting());
  458. }
  459. else {
  460. throw new Error("You've enabled schema reporting by setting the APOLLO_SCHEMA_REPORTING " +
  461. 'environment variable to true, but you also need to provide your ' +
  462. 'Apollo API key, via the APOLLO_KEY environment ' +
  463. 'variable or via `new ApolloServer({apollo: {key})');
  464. }
  465. }
  466. }
  467. {
  468. const alreadyHavePlugin = alreadyHavePluginWithInternalId('InlineTrace');
  469. if (!alreadyHavePlugin) {
  470. const { ApolloServerPluginInlineTrace } = await Promise.resolve().then(() => __importStar(require('./plugin/inlineTrace/index.js')));
  471. plugins.push(ApolloServerPluginInlineTrace({ __onlyIfSchemaIsSubgraph: true }));
  472. }
  473. }
  474. const alreadyHavePlugin = alreadyHavePluginWithInternalId('LandingPageDisabled');
  475. if (!alreadyHavePlugin) {
  476. const { ApolloServerPluginLandingPageLocalDefault, ApolloServerPluginLandingPageProductionDefault, } = await Promise.resolve().then(() => __importStar(require('./plugin/landingPage/default/index.js')));
  477. const plugin = isDev
  478. ? ApolloServerPluginLandingPageLocalDefault()
  479. : ApolloServerPluginLandingPageProductionDefault();
  480. if (!isImplicitlyInstallablePlugin(plugin)) {
  481. throw Error('default landing page plugin should be implicitly installable?');
  482. }
  483. plugin.__internal_installed_implicitly__ = true;
  484. plugins.push(plugin);
  485. }
  486. }
  487. addPlugin(plugin) {
  488. if (this.internals.state.phase !== 'initialized') {
  489. throw new Error("Can't add plugins after the server has started");
  490. }
  491. this.internals.plugins.push(plugin);
  492. }
  493. async executeHTTPGraphQLRequest({ httpGraphQLRequest, context, }) {
  494. try {
  495. let runningServerState;
  496. try {
  497. runningServerState = await this._ensureStarted();
  498. }
  499. catch (error) {
  500. return await this.errorResponse(error, httpGraphQLRequest);
  501. }
  502. if (runningServerState.landingPage &&
  503. this.prefersHTML(httpGraphQLRequest)) {
  504. let renderedHtml;
  505. if (typeof runningServerState.landingPage.html === 'string') {
  506. renderedHtml = runningServerState.landingPage.html;
  507. }
  508. else {
  509. try {
  510. renderedHtml = await runningServerState.landingPage.html();
  511. }
  512. catch (maybeError) {
  513. const error = (0, errorNormalize_js_1.ensureError)(maybeError);
  514. this.logger.error(`Landing page \`html\` function threw: ${error}`);
  515. return await this.errorResponse(error, httpGraphQLRequest);
  516. }
  517. }
  518. return {
  519. headers: new HeaderMap_js_1.HeaderMap([['content-type', 'text/html']]),
  520. body: {
  521. kind: 'complete',
  522. string: renderedHtml,
  523. },
  524. };
  525. }
  526. if (this.internals.csrfPreventionRequestHeaders) {
  527. (0, preventCsrf_js_1.preventCsrf)(httpGraphQLRequest.headers, this.internals.csrfPreventionRequestHeaders);
  528. }
  529. let contextValue;
  530. try {
  531. contextValue = await context();
  532. }
  533. catch (maybeError) {
  534. const error = (0, errorNormalize_js_1.ensureError)(maybeError);
  535. try {
  536. await Promise.all(this.internals.plugins.map(async (plugin) => plugin.contextCreationDidFail?.({
  537. error,
  538. })));
  539. }
  540. catch (pluginError) {
  541. this.logger.error(`contextCreationDidFail hook threw: ${pluginError}`);
  542. }
  543. return await this.errorResponse((0, errorNormalize_js_1.ensureGraphQLError)(error, 'Context creation failed: '), httpGraphQLRequest);
  544. }
  545. return await (0, httpBatching_js_1.runPotentiallyBatchedHttpQuery)(this, httpGraphQLRequest, contextValue, runningServerState.schemaManager.getSchemaDerivedData(), this.internals);
  546. }
  547. catch (maybeError_) {
  548. const maybeError = maybeError_;
  549. if (maybeError instanceof graphql_1.GraphQLError &&
  550. maybeError.extensions.code === index_js_1.ApolloServerErrorCode.BAD_REQUEST) {
  551. try {
  552. await Promise.all(this.internals.plugins.map(async (plugin) => plugin.invalidRequestWasReceived?.({ error: maybeError })));
  553. }
  554. catch (pluginError) {
  555. this.logger.error(`invalidRequestWasReceived hook threw: ${pluginError}`);
  556. }
  557. }
  558. return await this.errorResponse(maybeError, httpGraphQLRequest);
  559. }
  560. }
  561. async errorResponse(error, requestHead) {
  562. const { formattedErrors, httpFromErrors } = (0, errorNormalize_js_1.normalizeAndFormatErrors)([error], {
  563. includeStacktraceInErrorResponses: this.internals.includeStacktraceInErrorResponses,
  564. formatError: this.internals.formatError,
  565. });
  566. return {
  567. status: httpFromErrors.status ?? 500,
  568. headers: new HeaderMap_js_1.HeaderMap([
  569. ...httpFromErrors.headers,
  570. [
  571. 'content-type',
  572. chooseContentTypeForSingleResultResponse(requestHead) ??
  573. exports.MEDIA_TYPES.APPLICATION_JSON,
  574. ],
  575. ]),
  576. body: {
  577. kind: 'complete',
  578. string: await this.internals.stringifyResult({
  579. errors: formattedErrors,
  580. }),
  581. },
  582. };
  583. }
  584. prefersHTML(request) {
  585. const acceptHeader = request.headers.get('accept');
  586. return (request.method === 'GET' &&
  587. !!acceptHeader &&
  588. new negotiator_1.default({
  589. headers: { accept: acceptHeader },
  590. }).mediaType([
  591. exports.MEDIA_TYPES.APPLICATION_JSON,
  592. exports.MEDIA_TYPES.APPLICATION_GRAPHQL_RESPONSE_JSON,
  593. exports.MEDIA_TYPES.MULTIPART_MIXED_EXPERIMENTAL,
  594. exports.MEDIA_TYPES.MULTIPART_MIXED_NO_DEFER_SPEC,
  595. exports.MEDIA_TYPES.TEXT_HTML,
  596. ]) === exports.MEDIA_TYPES.TEXT_HTML);
  597. }
  598. async executeOperation(request, options = {}) {
  599. if (this.internals.state.phase === 'initialized') {
  600. await this.start();
  601. }
  602. const schemaDerivedData = (await this._ensureStarted()).schemaManager.getSchemaDerivedData();
  603. const graphQLRequest = {
  604. ...request,
  605. query: request.query && typeof request.query !== 'string'
  606. ? (0, graphql_1.print)(request.query)
  607. : request.query,
  608. };
  609. const response = await internalExecuteOperation({
  610. server: this,
  611. graphQLRequest,
  612. internals: this.internals,
  613. schemaDerivedData,
  614. sharedResponseHTTPGraphQLHead: null,
  615. }, options);
  616. return response;
  617. }
  618. }
  619. exports.ApolloServer = ApolloServer;
  620. async function internalExecuteOperation({ server, graphQLRequest, internals, schemaDerivedData, sharedResponseHTTPGraphQLHead, }, options) {
  621. const requestContext = {
  622. logger: server.logger,
  623. cache: server.cache,
  624. schema: schemaDerivedData.schema,
  625. request: graphQLRequest,
  626. response: {
  627. http: sharedResponseHTTPGraphQLHead ?? (0, runHttpQuery_js_1.newHTTPGraphQLHead)(),
  628. },
  629. contextValue: cloneObject(options?.contextValue ?? {}),
  630. metrics: {},
  631. overallCachePolicy: (0, cachePolicy_js_1.newCachePolicy)(),
  632. requestIsBatched: sharedResponseHTTPGraphQLHead !== null,
  633. };
  634. try {
  635. return await (0, requestPipeline_js_1.processGraphQLRequest)(schemaDerivedData, server, internals, requestContext);
  636. }
  637. catch (maybeError) {
  638. const error = (0, errorNormalize_js_1.ensureError)(maybeError);
  639. await Promise.all(internals.plugins.map(async (plugin) => plugin.unexpectedErrorProcessingRequest?.({
  640. requestContext,
  641. error,
  642. })));
  643. server.logger.error(`Unexpected error processing request: ${error}`);
  644. throw new Error('Internal server error');
  645. }
  646. }
  647. exports.internalExecuteOperation = internalExecuteOperation;
  648. function isImplicitlyInstallablePlugin(p) {
  649. return '__internal_installed_implicitly__' in p;
  650. }
  651. exports.isImplicitlyInstallablePlugin = isImplicitlyInstallablePlugin;
  652. exports.MEDIA_TYPES = {
  653. APPLICATION_JSON: 'application/json; charset=utf-8',
  654. APPLICATION_JSON_GRAPHQL_CALLBACK: 'application/json; callbackSpec=1.0; charset=utf-8',
  655. APPLICATION_GRAPHQL_RESPONSE_JSON: 'application/graphql-response+json; charset=utf-8',
  656. MULTIPART_MIXED_NO_DEFER_SPEC: 'multipart/mixed',
  657. MULTIPART_MIXED_EXPERIMENTAL: 'multipart/mixed; deferSpec=20220824',
  658. TEXT_HTML: 'text/html',
  659. };
  660. function chooseContentTypeForSingleResultResponse(head) {
  661. const acceptHeader = head.headers.get('accept');
  662. if (!acceptHeader) {
  663. return exports.MEDIA_TYPES.APPLICATION_JSON;
  664. }
  665. else {
  666. const preferred = new negotiator_1.default({
  667. headers: { accept: head.headers.get('accept') },
  668. }).mediaType([
  669. exports.MEDIA_TYPES.APPLICATION_JSON,
  670. exports.MEDIA_TYPES.APPLICATION_GRAPHQL_RESPONSE_JSON,
  671. exports.MEDIA_TYPES.APPLICATION_JSON_GRAPHQL_CALLBACK,
  672. ]);
  673. if (preferred) {
  674. return preferred;
  675. }
  676. else {
  677. return null;
  678. }
  679. }
  680. }
  681. exports.chooseContentTypeForSingleResultResponse = chooseContentTypeForSingleResultResponse;
  682. function cloneObject(object) {
  683. return Object.assign(Object.create(Object.getPrototypeOf(object)), object);
  684. }
  685. //# sourceMappingURL=ApolloServer.js.map