@apollo/federation
Version:
Apollo Federation Utilities
59 lines (51 loc) • 2.45 kB
text/typescript
import { isObjectType, FieldNode, GraphQLError } from 'graphql';
import { logServiceAndType, errorWithCode, getFederationMetadata, findTypeNodeInServiceList, findSelectionSetOnNode, isDirectiveDefinitionNode, printFieldSet } from '../../utils';
import { PostCompositionValidator } from '.';
/**
* - The fields argument can not select fields that were overwritten by another service
*/
export const keyFieldsMissingOnBase: PostCompositionValidator = ({
schema,
serviceList,
}) => {
const errors: GraphQLError[] = [];
const types = schema.getTypeMap();
for (const [typeName, namedType] of Object.entries(types)) {
if (!isObjectType(namedType)) continue;
const typeFederationMetadata = getFederationMetadata(namedType);
if (typeFederationMetadata?.keys) {
const allFieldsInType = namedType.getFields();
for (const [serviceName, selectionSets = []] of Object.entries(
typeFederationMetadata.keys,
)) {
for (const selectionSet of selectionSets) {
for (const field of selectionSet as FieldNode[]) {
const name = field.name.value;
// find corresponding field for each selected field
const matchingField = allFieldsInType[name];
// NOTE: We don't need to warn if there is no matching field.
// keyFieldsSelectInvalidType already does that :)
if (matchingField) {
const typeNode = findTypeNodeInServiceList(typeName, serviceName, serviceList);
const selectionSetNode = !isDirectiveDefinitionNode(typeNode) ?
findSelectionSetOnNode(typeNode, 'key', printFieldSet(selectionSet)) : undefined;
const fieldFederationMetadata = getFederationMetadata(matchingField);
// warn if not from base type OR IF IT WAS OVERWITTEN
if (fieldFederationMetadata?.serviceName && fieldFederationMetadata.serviceName !== serviceName) {
errors.push(
errorWithCode(
'KEY_FIELDS_MISSING_ON_BASE',
logServiceAndType(serviceName, typeName) +
`A @key selects ${name}, but ${typeName}.${name} was either created or overwritten by ${fieldFederationMetadata.serviceName}, not ${serviceName}`,
selectionSetNode,
),
);
}
}
}
}
}
}
}
return errors;
};