@apollo/federation
Version:
Apollo Federation Utilities
66 lines (58 loc) • 2.33 kB
text/typescript
import { GraphQLError, isSpecifiedDirective } from 'graphql';
import {
errorWithCode,
logDirective,
getFederationMetadata,
} from '../../utils';
// Importing from 'dist' is not actually supported as part of the public API,
// but this allows us not to duplicate things in the meantime while the
// @apollo/federation package still exists.
import { isKnownSubgraphDirective } from '@apollo/subgraph/dist/directives';
import { PostCompositionValidator } from '.';
/**
* All custom directives with executable locations must be implemented in every
* service. This validator is not responsible for ensuring the directives are an
* ExecutableDirective, however composition ensures this by filtering out all
* TypeSystemDirectiveLocations.
*/
export const executableDirectivesInAllServices: PostCompositionValidator = ({
schema,
serviceList,
}) => {
const errors: GraphQLError[] = [];
const customExecutableDirectives = schema
.getDirectives()
.filter(x => !isKnownSubgraphDirective(x) && !isSpecifiedDirective(x));
customExecutableDirectives.forEach(directive => {
const directiveFederationMetadata = getFederationMetadata(directive);
if (!directiveFederationMetadata) return;
const allServiceNames = serviceList.map(({ name }) => name);
const serviceNamesWithDirective = Object.keys(
directiveFederationMetadata.directiveDefinitions,
);
const serviceNamesWithoutDirective = allServiceNames.reduce(
(without, serviceName) => {
if (!serviceNamesWithDirective.includes(serviceName)) {
without.push(serviceName);
}
return without;
},
[] as string[],
);
if (serviceNamesWithoutDirective.length > 0) {
errors.push(
errorWithCode(
'EXECUTABLE_DIRECTIVES_IN_ALL_SERVICES',
logDirective(directive.name) +
`Custom directives must be implemented in every service. The following services do not implement the @${
directive.name
} directive: ${serviceNamesWithoutDirective.join(', ')}.`,
// TODO (Issue #705): when we can associate locations to service names, we should expose
// locations of the services where this directive is not used
directive.astNode ?? undefined,
),
);
}
});
return errors;
};