Core schema transformation utilities for filtering, mapping, healing, and modifying GraphQL schemas. These tools are essential for schema stitching, federation, schema evolution, and creating custom schema processing pipelines.
Transform GraphQL schemas using mapper functions for different schema elements.
/**
* Transform a GraphQL schema using provided mapper functions
* @param schema - The schema to transform
* @param schemaMapper - Object containing mapper functions for different schema elements
* @returns Transformed schema
*/
function mapSchema(schema: GraphQLSchema, schemaMapper: SchemaMapper): GraphQLSchema;
interface SchemaMapper {
[MapperKind.TYPE]?: TypeMapper;
[MapperKind.SCALAR_TYPE]?: ScalarTypeMapper;
[MapperKind.ENUM_TYPE]?: EnumTypeMapper;
[MapperKind.COMPOSITE_TYPE]?: CompositeTypeMapper;
[MapperKind.OBJECT_TYPE]?: ObjectTypeMapper;
[MapperKind.INPUT_OBJECT_TYPE]?: InputObjectTypeMapper;
[MapperKind.ABSTRACT_TYPE]?: AbstractTypeMapper;
[MapperKind.UNION_TYPE]?: UnionTypeMapper;
[MapperKind.INTERFACE_TYPE]?: InterfaceTypeMapper;
[MapperKind.ROOT_OBJECT]?: ObjectTypeMapper;
[MapperKind.QUERY]?: ObjectTypeMapper;
[MapperKind.MUTATION]?: ObjectTypeMapper;
[MapperKind.SUBSCRIPTION]?: ObjectTypeMapper;
[MapperKind.OBJECT_FIELD]?: FieldMapper;
[MapperKind.ROOT_FIELD]?: FieldMapper;
[MapperKind.QUERY_ROOT_FIELD]?: FieldMapper;
[MapperKind.MUTATION_ROOT_FIELD]?: FieldMapper;
[MapperKind.SUBSCRIPTION_ROOT_FIELD]?: FieldMapper;
[MapperKind.INTERFACE_FIELD]?: FieldMapper;
[MapperKind.COMPOSITE_FIELD]?: FieldMapper;
[MapperKind.ARGUMENT]?: ArgumentMapper;
[MapperKind.INPUT_OBJECT_FIELD]?: InputFieldMapper;
[MapperKind.DIRECTIVE]?: DirectiveMapper;
[MapperKind.ENUM_VALUE]?: EnumValueMapper;
}
enum MapperKind {
TYPE = 'MapperKind.TYPE',
SCALAR_TYPE = 'MapperKind.SCALAR_TYPE',
ENUM_TYPE = 'MapperKind.ENUM_TYPE',
COMPOSITE_TYPE = 'MapperKind.COMPOSITE_TYPE',
OBJECT_TYPE = 'MapperKind.OBJECT_TYPE',
INPUT_OBJECT_TYPE = 'MapperKind.INPUT_OBJECT_TYPE',
ABSTRACT_TYPE = 'MapperKind.ABSTRACT_TYPE',
UNION_TYPE = 'MapperKind.UNION_TYPE',
INTERFACE_TYPE = 'MapperKind.INTERFACE_TYPE',
ROOT_OBJECT = 'MapperKind.ROOT_OBJECT',
QUERY = 'MapperKind.QUERY',
MUTATION = 'MapperKind.MUTATION',
SUBSCRIPTION = 'MapperKind.SUBSCRIPTION',
OBJECT_FIELD = 'MapperKind.OBJECT_FIELD',
ROOT_FIELD = 'MapperKind.ROOT_FIELD',
QUERY_ROOT_FIELD = 'MapperKind.QUERY_ROOT_FIELD',
MUTATION_ROOT_FIELD = 'MapperKind.MUTATION_ROOT_FIELD',
SUBSCRIPTION_ROOT_FIELD = 'MapperKind.SUBSCRIPTION_ROOT_FIELD',
INTERFACE_FIELD = 'MapperKind.INTERFACE_FIELD',
COMPOSITE_FIELD = 'MapperKind.COMPOSITE_FIELD',
ARGUMENT = 'MapperKind.ARGUMENT',
INPUT_OBJECT_FIELD = 'MapperKind.INPUT_OBJECT_FIELD',
DIRECTIVE = 'MapperKind.DIRECTIVE',
ENUM_VALUE = 'MapperKind.ENUM_VALUE'
}
type FieldMapper = (
fieldConfig: GraphQLFieldConfig<any, any>,
fieldName: string,
typeName: string,
schema: GraphQLSchema
) => GraphQLFieldConfig<any, any> | [string, GraphQLFieldConfig<any, any>] | null | undefined;
type ObjectTypeMapper = (
type: GraphQLObjectType,
schema: GraphQLSchema
) => GraphQLObjectType | null | undefined;
type ArgumentMapper = (
argumentConfig: GraphQLArgumentConfig,
fieldName: string,
typeName: string,
schema: GraphQLSchema
) => GraphQLArgumentConfig | [string, GraphQLArgumentConfig] | null | undefined;Usage Examples:
import { mapSchema, MapperKind } from "@graphql-tools/utils";
// Add logging to all field resolvers
const schemaWithLogging = mapSchema(schema, {
[MapperKind.OBJECT_FIELD]: (fieldConfig, fieldName, typeName) => {
const originalResolve = fieldConfig.resolve;
fieldConfig.resolve = async (source, args, context, info) => {
console.log(`Resolving ${typeName}.${fieldName}`);
return originalResolve ? originalResolve(source, args, context, info) : source[fieldName];
};
return fieldConfig;
}
});
// Rename all fields to camelCase
const camelCaseSchema = mapSchema(schema, {
[MapperKind.OBJECT_FIELD]: (fieldConfig, fieldName) => {
const camelFieldName = fieldName.replace(/_([a-z])/g, (g) => g[1].toUpperCase());
return [camelFieldName, fieldConfig];
}
});Filter GraphQL schemas to remove unwanted types, fields, or other elements.
/**
* Filter a GraphQL schema based on provided filter functions
* @param options - Filtering options and filter functions
* @returns Filtered schema
*/
function filterSchema(options: FilterSchemaOptions): GraphQLSchema;
interface FilterSchemaOptions {
schema: GraphQLSchema;
typeFilter?: FilterTypes;
fieldFilter?: FilterObjectFields;
rootFieldFilter?: FilterRootFields;
objectFieldFilter?: FilterObjectFields;
interfaceFieldFilter?: FilterInterfaceFields;
inputFieldFilter?: FilterInputObjectFields;
argumentFilter?: FilterArguments;
directiveFilter?: FilterDirectives;
}
type FilterTypes = (typeName: string, type: GraphQLNamedType) => boolean;
type FilterObjectFields = (typeName: string, fieldName: string, fieldConfig: GraphQLFieldConfig<any, any>) => boolean;
type FilterRootFields = (operation: 'Query' | 'Mutation' | 'Subscription', fieldName: string, fieldConfig: GraphQLFieldConfig<any, any>) => boolean;
type FilterInterfaceFields = (typeName: string, fieldName: string, fieldConfig: GraphQLFieldConfig<any, any>) => boolean;
type FilterInputObjectFields = (typeName: string, fieldName: string, inputFieldConfig: GraphQLInputFieldConfig) => boolean;
type FilterArguments = (typeName: string, fieldName: string, argName: string, argConfig: GraphQLArgumentConfig) => boolean;
type FilterDirectives = (directiveName: string, directive: GraphQLDirective) => boolean;Usage Examples:
import { filterSchema } from "@graphql-tools/utils";
// Remove deprecated fields and types
const cleanSchema = filterSchema({
schema: originalSchema,
fieldFilter: (typeName, fieldName, fieldConfig) => {
return !fieldConfig.deprecationReason;
},
typeFilter: (typeName, type) => {
return !type.description?.includes('@deprecated');
}
});
// Keep only specific root fields
const publicSchema = filterSchema({
schema: originalSchema,
rootFieldFilter: (operation, fieldName) => {
const publicFields = ['user', 'posts', 'comments'];
return publicFields.includes(fieldName);
}
});Heal GraphQL schemas by restoring proper type references and fixing inconsistencies.
/**
* Heal a GraphQL schema by restoring proper type references and fixing inconsistencies
* @param schema - The schema to heal
* @returns Healed schema with restored references
*/
function healSchema(schema: GraphQLSchema): GraphQLSchema;Usage Examples:
import { healSchema } from "@graphql-tools/utils";
// Heal schema after manual modifications
const modifiedSchema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Query',
fields: {
// ... manually created fields that might have broken references
}
})
});
const healedSchema = healSchema(modifiedSchema);Remove unused types and fields from GraphQL schemas to optimize schema size.
/**
* Remove unused types and fields from a GraphQL schema
* @param schema - The schema to prune
* @param options - Pruning options
* @returns Pruned schema with unused elements removed
*/
function pruneSchema(schema: GraphQLSchema, options?: PruneSchemaOptions): GraphQLSchema;
interface PruneSchemaOptions {
skipPruning?: PruneSchemaFilter;
skipEmptyCompositeTypePruning?: boolean;
skipEmptyUnionPruning?: boolean;
skipUnimplementedAbstractTypePruning?: boolean;
skipUnusedTypesPruning?: boolean;
}
type PruneSchemaFilter = (typeName: string) => boolean;Usage Examples:
import { pruneSchema } from "@graphql-tools/utils";
// Remove all unused types and fields
const prunedSchema = pruneSchema(schema);
// Prune but keep specific types
const selectivelyPruned = pruneSchema(schema, {
skipPruning: (typeName) => {
const keepTypes = ['User', 'Post', 'Comment'];
return keepTypes.includes(typeName);
}
});Update type references throughout a GraphQL schema.
/**
* Update type references throughout a GraphQL schema
* @param schema - The schema to rewire
* @param typeMap - Map of old type names to new types
* @returns Schema with updated type references
*/
function rewireTypes(schema: GraphQLSchema, typeMap: Record<string, GraphQLNamedType>): GraphQLSchema;Add new type definitions to an existing GraphQL schema.
/**
* Add type definitions to an existing GraphQL schema
* @param schema - The base schema
* @param newTypes - Array of new types to add
* @returns Schema with added types
*/
function addTypes(schema: GraphQLSchema, newTypes: GraphQLNamedType[]): GraphQLSchema;Usage Examples:
import { addTypes } from "@graphql-tools/utils";
import { GraphQLObjectType, GraphQLString } from "graphql";
// Add a new type to existing schema
const newType = new GraphQLObjectType({
name: 'NewType',
fields: {
message: { type: GraphQLString }
}
});
const extendedSchema = addTypes(schema, [newType]);