@apollo/federation
Version:
Apollo Federation Utilities
83 lines (74 loc) • 2.6 kB
text/typescript
import {
GraphQLError,
visit,
ObjectTypeDefinitionNode,
ObjectTypeExtensionNode,
} from 'graphql';
import { ServiceDefinition, DefaultRootOperationTypeName } from '../../types';
import {
logServiceAndType,
errorWithCode,
defaultRootOperationNameLookup
} from '../../utils';
/**
* - When a schema definition or extension is provided, warn user against using
* default root operation type names for types or extensions
* (Query, Mutation, Subscription)
*/
export const rootFieldUsed = ({
name: serviceName,
typeDefs,
}: ServiceDefinition) => {
const errors: GraphQLError[] = [];
// Array of default root operation names
const defaultRootOperationNames = Object.values(
defaultRootOperationNameLookup,
);
const disallowedTypeNames: {
[key in DefaultRootOperationTypeName]?: boolean;
} = {};
let hasSchemaDefinitionOrExtension = false;
visit(typeDefs, {
OperationTypeDefinition(node) {
// If we find at least one root operation type definition, we know the user has
// specified either a schema definition or extension.
hasSchemaDefinitionOrExtension = true;
if (
!defaultRootOperationNames.includes(node.type.name
.value as DefaultRootOperationTypeName)
) {
disallowedTypeNames[
defaultRootOperationNameLookup[node.operation]
] = true;
}
},
});
// If a schema or schema extension is defined, we need to warn for each improper
// usage of default root operation names. The conditions for an improper usage are:
// 1. root operation type is defined as a non-default name (i.e. query: RootQuery)
// 2. the respective default operation type name is used as a regular type
if (hasSchemaDefinitionOrExtension) {
visit(typeDefs, {
ObjectTypeDefinition: visitType,
ObjectTypeExtension: visitType,
});
function visitType(
node: ObjectTypeDefinitionNode | ObjectTypeExtensionNode,
) {
if (
disallowedTypeNames[node.name.value as DefaultRootOperationTypeName]
) {
const rootOperationName = node.name.value;
errors.push(
errorWithCode(
`ROOT_${rootOperationName.toUpperCase()}_USED`,
logServiceAndType(serviceName, rootOperationName) +
`Found invalid use of default root operation name \`${rootOperationName}\`. \`${rootOperationName}\` is disallowed when \`Schema.${rootOperationName.toLowerCase()}\` is set to a type other than \`${rootOperationName}\`.`,
node,
),
);
}
}
}
return errors;
};