UNPKG

@apollo/gateway

Version:
84 lines (75 loc) 2.73 kB
import { parse } from 'graphql'; import { Headers, type HeadersInit } from 'node-fetch'; import { ServiceDefinition } from '@apollo/federation-internals'; import { GraphQLDataSource, GraphQLDataSourceRequestKind } from '../../datasources/types'; import { SERVICE_DEFINITION_QUERY } from '../..'; import { ServiceDefinitionUpdate, ServiceEndpointDefinition } from '../../config'; import { GatewayGraphQLRequest } from '@apollo/server-gateway-interface'; export type Service = ServiceEndpointDefinition & { dataSource: GraphQLDataSource; }; export async function loadServicesFromRemoteEndpoint({ serviceList, getServiceIntrospectionHeaders, serviceSdlCache, }: { serviceList: Service[]; getServiceIntrospectionHeaders: ( service: ServiceEndpointDefinition, ) => Promise<HeadersInit | undefined>; serviceSdlCache: Map<string, string>; }): Promise<ServiceDefinitionUpdate> { if (!serviceList || !serviceList.length) { throw new Error( 'Tried to load services from remote endpoints but none provided', ); } let isNewSchema = false; // for each service, fetch its introspection schema const promiseOfServiceList = serviceList.map(async ({ name, url, dataSource }) => { if (!url) { throw new Error( `Tried to load schema for '${name}' but no 'url' was specified.`); } const request: GatewayGraphQLRequest = { query: SERVICE_DEFINITION_QUERY, http: { url, method: 'POST', headers: new Headers(await getServiceIntrospectionHeaders({ name, url })), }, }; return dataSource .process({ kind: GraphQLDataSourceRequestKind.LOADING_SCHEMA, request, context: {}, }) .then(({ data, errors }): ServiceDefinition => { if (data && !errors) { const typeDefs = data._service.sdl as string; const previousDefinition = serviceSdlCache.get(name); // this lets us know if any downstream service has changed // and we need to recalculate the schema if (previousDefinition !== typeDefs) { isNewSchema = true; } serviceSdlCache.set(name, typeDefs); return { name, url, typeDefs: parse(typeDefs), }; } throw new Error(errors?.map((e) => e.message).join('\n')); }) .catch((err) => { const errorMessage = `Couldn't load service definitions for "${name}" at ${url}` + (err && err.message ? ': ' + err.message || err : ''); throw new Error(errorMessage); }); }); const serviceDefinitions = await Promise.all(promiseOfServiceList); return { serviceDefinitions, isNewSchema } }