Issue workflow progress
Describe the bug
The @graphql-tools/import package fails to process schemas with Federation v2 directives due to insufficient directive recognition in its core validation logic. This is a critical issue because:
- When a GraphQL schema uses
#import statements, the GraphQL loader chain exclusively delegates to processImport from @graphql-tools/import
- The directive validation in
processImport checks against a fixed array of builtinDirectives that's missing Federation v2 directives
- The validation fails on line 584 of
index.js where it calls: if (!builtinDirectives.includes(directiveName)) { for directives like @shareable, @tag, etc.
Interestingly, the package already defines a Federation-related array that's never used for validation:
// in @graphql-tools/import/cjs/index.js
const federationImports = [
'@composeDirective',
'@extends',
'@external',
'@inaccessible',
'@interfaceObject',
'@key',
'@override',
'@provides',
'@requires',
'@shareable',
'@tag',
'FieldSet',
];
However:
- This array is never referenced during directive validation (the code at line 584 only checks against builtinDirectives)
- Even if it were used, it's still missing several Federation v2 directives like @link, and Apollo directives like @connect, @source, etc.
- The directive names include the @ symbol, which doesn't match how they're referenced during validation
This issue creates a complete roadblock for projects using both Federation v2 and schema imports, as there is no alternative path for handling imports - the only code path triggers validation failures.
To Reproduce
Create a GraphQL schema with imports and Federation v2 directives:
# main.graphql
import User from './user.graphql'
type Query {
getUser(id: ID!): User
}
# user.graphql
type User @key(fields: "id") {
id: ID!
name: String @shareable
email: String @inaccessible
role: String @tag(name: "internal")
}
Load the schema with the standard GraphQL tools chain:
const { loadSchema } = require('@graphql-tools/load');
const { GraphQLFileLoader } = require('@graphql-tools/graphql-file-loader');
async function loadGraphQLSchema() {
try {
const schema = await loadSchema('./main.graphql', {
loaders: [new GraphQLFileLoader()]
});
console.log('Schema loaded successfully');
} catch (error) {
console.error('Failed to load schema:', error.message);
// Fails with: Couldn't find type tag in any of the schemas.
}
}
Expected behavior
The schema loading process should successfully recognize Federation v2 directives (e.g., @Shareable, @tag, @inaccessible) as valid built-in directives. These directives should be part of the builtinDirectives array in @graphql-tools/import, allowing the processImport function to properly
handle schemas that use Federation v2 features.
Environment:
- OS: macOS Ventura
- @graphql-tools/import: 7.0.0
- @graphql-tools/load: ^7.0.0
- @graphql-tools/graphql-file-loader: ^7.0.0
- NodeJS: 18.x
Additional context
The technical root of the issue is in index.js of @graphql-tools/import where the built-in directives are defined:
const builtinDirectives = [
'deprecated',
'skip',
'include',
'cacheControl',
'connection',
'client',
'specifiedBy',
...federationV1Directives,
];
It only includes Federation v1 directives (key, provides, requires, external) but completely omits Federation v2 directives like:
const federationV2Directives = [
'extends',
'tag',
'shareable',
'inaccessible',
'override',
'interfaceObject',
'composeDirective',
'link',
];
And Apollo Connectors/Router directives:
const apolloConnectorsDirectives = [
'connect',
'source',
'authenticated',
'requiresScopes',
'policy',
];
The federationImports array defined in the module is not connected to the directive validation logic - it appears to be used for something else entirely, and isn't helping with the directive validation.
We've implemented a workaround by patching the module at runtime using Module._load interception:
// This is our patched module that intercepts loading of @graphql-tools/import
// and extends the builtinDirectives array to include Federation v2 directives
const Module = require('module');
const originalLoad = Module._load;
Module._load = function(request, parent) {
const exports = originalLoad.apply(this, arguments);
if (request === '@graphql-tools/import' && parent && parent.path) {
const resolvedPath = require.resolve('@graphql-tools/import', {
paths: [parent.path],
});
if (resolvedPath) {
// Use rewire to modify the internal builtinDirectives array
const rewire = require('rewire');
const patchedModule = rewire(resolvedPath);
const builtinDirectives = patchedModule.__get__('builtinDirectives');
// Add Federation v2 and Apollo directives
[
'extends', 'tag', 'shareable', 'inaccessible', 'override',
'interfaceObject', 'composeDirective', 'link', 'connect',
'source', 'authenticated', 'requiresScopes', 'policy'
].forEach(directive => {
if (!builtinDirectives.includes(directive)) {
builtinDirectives.push(directive);
}
});
// Replace the processImport function on the cached module
require.cache[resolvedPath].exports.processImport = patchedModule.processImport;
}
}
return exports;
};
However, this is obviously not sustainable as it requires runtime patching of the module system, which has its own complications. The proper fix would be to add support for all Federation v2 directives directly in the @graphql-tools/import package's builtinDirectives array.
Issue workflow progress
Describe the bug
The
@graphql-tools/importpackage fails to process schemas with Federation v2 directives due to insufficient directive recognition in its core validation logic. This is a critical issue because:#importstatements, the GraphQL loader chain exclusively delegates toprocessImportfrom@graphql-tools/importprocessImportchecks against a fixed array ofbuiltinDirectivesthat's missing Federation v2 directivesindex.jswhere it calls:if (!builtinDirectives.includes(directiveName)) {for directives like@shareable,@tag, etc.Interestingly, the package already defines a Federation-related array that's never used for validation:
However:
This issue creates a complete roadblock for projects using both Federation v2 and schema imports, as there is no alternative path for handling imports - the only code path triggers validation failures.
To Reproduce
Create a GraphQL schema with imports and Federation v2 directives:
Expected behavior
The schema loading process should successfully recognize Federation v2 directives (e.g., @Shareable, @tag, @inaccessible) as valid built-in directives. These directives should be part of the builtinDirectives array in @graphql-tools/import, allowing the processImport function to properly
handle schemas that use Federation v2 features.
Environment:
Additional context
The technical root of the issue is in index.js of @graphql-tools/import where the built-in directives are defined:
const builtinDirectives = [
'deprecated',
'skip',
'include',
'cacheControl',
'connection',
'client',
'specifiedBy',
...federationV1Directives,
];
It only includes Federation v1 directives (key, provides, requires, external) but completely omits Federation v2 directives like:
const federationV2Directives = [
'extends',
'tag',
'shareable',
'inaccessible',
'override',
'interfaceObject',
'composeDirective',
'link',
];
And Apollo Connectors/Router directives:
const apolloConnectorsDirectives = [
'connect',
'source',
'authenticated',
'requiresScopes',
'policy',
];
The federationImports array defined in the module is not connected to the directive validation logic - it appears to be used for something else entirely, and isn't helping with the directive validation.
We've implemented a workaround by patching the module at runtime using Module._load interception:
// This is our patched module that intercepts loading of @graphql-tools/import
// and extends the builtinDirectives array to include Federation v2 directives
const Module = require('module');
const originalLoad = Module._load;
Module._load = function(request, parent) {
const exports = originalLoad.apply(this, arguments);
};
However, this is obviously not sustainable as it requires runtime patching of the module system, which has its own complications. The proper fix would be to add support for all Federation v2 directives directly in the @graphql-tools/import package's builtinDirectives array.