UNPKG

@graphql-mesh/merger-federation

Version:
121 lines (117 loc) 5.07 kB
'use strict'; const graphql = require('graphql'); const wrap = require('@graphql-tools/wrap'); const gateway = require('@apollo/gateway'); const schema = require('@graphql-tools/schema'); const utils = require('@graphql-mesh/utils'); const utils$1 = require('@graphql-tools/utils'); const store = require('@graphql-mesh/store'); const crossHelpers = require('@graphql-mesh/cross-helpers'); class FederationMerger { constructor(options) { this.name = 'federation'; this.logger = options.logger; this.cache = options.cache; this.pubsub = options.pubsub; this.store = options.store; } async getUnifiedSchema({ rawSources, typeDefs, resolvers }) { this.logger.debug(`Creating localServiceList for gateway`); const rawSourceMap = new Map(); const localServiceList = []; const sourceMap = new Map(); await Promise.all(rawSources.map(async (rawSource) => { const transformedSchema = wrap.wrapSchema(rawSource); rawSourceMap.set(rawSource.name, rawSource); sourceMap.set(rawSource, transformedSchema); const sdl = await this.store .proxy(`${rawSource.name}_sdl`, store.PredefinedProxyOptions.StringWithoutValidation) .getWithSet(async () => { var _a; this.logger.debug(`Fetching Apollo Federated Service SDL for ${rawSource.name}`); const sdlQueryResult = await graphql.execute({ schema: transformedSchema, document: graphql.parse(gateway.SERVICE_DEFINITION_QUERY), }); if ((_a = sdlQueryResult.errors) === null || _a === void 0 ? void 0 : _a.length) { throw new utils$1.AggregateError(sdlQueryResult.errors, `Failed on fetching Federated SDL for ${rawSource.name}`); } return sdlQueryResult.data._service.sdl; }); localServiceList.push({ name: rawSource.name, typeDefs: graphql.parse(sdl), }); })); this.logger.debug(`Creating ApolloGateway`); const gateway$1 = new gateway.ApolloGateway({ localServiceList, buildService: ({ name }) => { this.logger.debug(`Building federation service: ${name}`); const rawSource = rawSourceMap.get(name); const transformedSchema = sourceMap.get(rawSource); return new gateway.LocalGraphQLDataSource(transformedSchema); }, logger: this.logger, debug: !!crossHelpers.process.env.DEBUG, serviceHealthCheck: true, }); this.logger.debug(`Loading gateway`); const { schema: schema$1, executor: gatewayExecutor } = await gateway$1.load(); const schemaHash = utils$1.printSchemaWithDirectives(schema$1); let remoteSchema = schema$1; this.logger.debug(`Wrapping gateway executor in a unified schema`); const executor = ({ document, info, variables, context, operationName }) => { const documentStr = utils.printWithCache(document); const { operation } = info; // const operationName = operation.name?.value; return gatewayExecutor({ document, request: { query: documentStr, operationName, variables, }, operationName, cache: this.cache, context, queryHash: documentStr, logger: this.logger, metrics: {}, source: documentStr, operation, schema: schema$1, schemaHash, overallCachePolicy: undefined, }); }; const id = this.pubsub.subscribe('destroy', async () => { this.pubsub.unsubscribe(id); await gateway$1.stop(); }); this.logger.debug(`Applying additionalTypeDefs`); typeDefs === null || typeDefs === void 0 ? void 0 : typeDefs.forEach(typeDef => { remoteSchema = graphql.extendSchema(remoteSchema, typeDef); }); if (resolvers) { this.logger.debug(`Applying additionalResolvers`); for (const resolversObj of utils$1.asArray(resolvers)) { remoteSchema = schema.addResolversToSchema({ schema: remoteSchema, resolvers: resolversObj, updateResolversInPlace: true, }); } } this.logger.debug(`Attaching sourceMap to the unified schema`); remoteSchema.extensions = remoteSchema.extensions || {}; Object.defineProperty(remoteSchema.extensions, 'sourceMap', { get: () => sourceMap, }); return { schema: remoteSchema, executor, }; } } module.exports = FederationMerger;