@harmonyjs/controller-apollo-gateway
Version:
Apollo Gateway controller for Harmony
94 lines (93 loc) • 4.14 kB
JavaScript
import { ApolloGateway, RemoteGraphQLDataSource, } from '@apollo/gateway';
import { ApolloServer } from '@harmonyjs/apollo-fastify';
let gatewayReference = null;
let firstComposition = true;
function didUpdateComposition(callback, serviceNumber) {
return function (services) {
if (services.serviceDefinitions.length === serviceNumber && !firstComposition) {
callback();
}
firstComposition = false;
};
}
/*
* The Apollo Controller exposes a GraphQL endpoint through an Apollo Server
*/
const ControllerApolloGateway = function (config) {
return ({
name: 'ControllerApolloGateway',
async initialize({ server, logger }) {
const { path, enablePlayground, services, authentication, gatewayConfig, apolloConfig, routeConfig, } = config;
logger.info('Registering GraphQL Federation endpoint...');
const gateway = gatewayReference || new ApolloGateway({
...(gatewayConfig || {}),
serviceList: services,
buildService({ url }) {
return new RemoteGraphQLDataSource({
url,
willSendRequest({ request, context }) {
if (context.headers) {
Object.keys(context.headers).forEach((header) => {
request.http.headers.set(header, context.headers[header]);
});
}
},
});
},
});
if (config.servicePoller) {
if (!gatewayReference) {
logger.warn('Service polling enabled');
logger.warn('This is a development feature only. Do not use in production!');
}
firstComposition = true;
gatewayReference = gateway;
gatewayReference.experimental_pollInterval = 1000;
gatewayReference.logger.disableAll(true);
gatewayReference.startPollingServices();
gatewayReference.experimental_didUpdateComposition = didUpdateComposition(config.servicePoller, config.services.length);
}
const apolloServer = new ApolloServer({
...(apolloConfig || {}),
gateway,
playground: !!enablePlayground,
introspection: !!enablePlayground,
context: ({ request }) => ({
headers: request.headers,
}),
subscriptions: false,
});
const routeOptions = { ...(routeConfig || {}) };
if (authentication) {
// @ts-ignore
if (!server[authentication.validator]) {
logger.error('The provided authentication controller was not initialized');
logger.error(`Make sure the authentication controller ${authentication().name} is present in your controllers array and is before ${this.name}`);
throw new Error('Missing controller');
}
const preValidation = [];
if (routeOptions.preValidation) {
if (Array.isArray(routeOptions.preValidation)) {
preValidation.push(...routeOptions.preValidation);
}
else {
preValidation.push(routeOptions.preValidation);
}
}
// @ts-ignore
preValidation.push(server[authentication.validator].try);
routeOptions.preValidation = preValidation;
}
await server.register(apolloServer.createHandler({
path,
cors: true,
routeOptions,
}));
logger.info(`GraphQL endpoint at ${path}`);
if (enablePlayground) {
logger.info(`GraphQL playground at ${path}`);
}
},
});
};
export default ControllerApolloGateway;