@graphql-tools/federation
Version:
Useful tools to create and manipulate GraphQL schemas.
127 lines (121 loc) • 4.54 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildSubgraphSchema = exports.SubgraphBaseSDL = void 0;
const graphql_1 = require("graphql");
const value_or_promise_1 = require("value-or-promise");
const merge_1 = require("@graphql-tools/merge");
const schema_1 = require("@graphql-tools/schema");
const utils_1 = require("@graphql-tools/utils");
exports.SubgraphBaseSDL = `
scalar _Any
scalar _FieldSet
scalar link__Import
enum link__Purpose {
SECURITY
EXECUTION
}
type _Service {
sdl: String!
}
type Query {
_service: _Service!
}
directive @external on FIELD_DEFINITION | OBJECT
directive @requires(fields: _FieldSet!) on FIELD_DEFINITION
directive @provides(fields: _FieldSet!) on FIELD_DEFINITION
directive @key(fields: _FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE
directive @link(
url: String!
as: String
for: link__Purpose
import: [link__Import]
) repeatable on SCHEMA
directive @shareable repeatable on OBJECT | FIELD_DEFINITION
directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
directive @tag(
name: String!
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
directive @override(from: String!) on FIELD_DEFINITION
directive @composeDirective(name: String!) repeatable on SCHEMA
directive @extends on OBJECT | INTERFACE
`;
function buildSubgraphSchema(optsOrModules) {
const opts = Array.isArray(optsOrModules)
? {
typeDefs: optsOrModules.map(opt => opt.typeDefs),
resolvers: optsOrModules.map(opt => opt.resolvers).flat(),
}
: optsOrModules;
const entityTypeNames = [];
function handleEntity(node) {
if (node.directives?.some(directive => directive.name.value === 'key')) {
entityTypeNames.push(node.name.value);
}
}
const typeDefs = (0, graphql_1.visit)((0, merge_1.mergeTypeDefs)([exports.SubgraphBaseSDL, opts.typeDefs]), {
ObjectTypeDefinition: node => {
handleEntity(node);
},
ObjectTypeExtension: node => {
handleEntity(node);
return {
...node,
kind: graphql_1.Kind.OBJECT_TYPE_DEFINITION,
directives: [
...(node.directives || []),
{
kind: 'Directive',
name: {
kind: 'Name',
value: 'extends',
},
},
],
};
},
});
const givenResolvers = (0, merge_1.mergeResolvers)(opts.resolvers);
const allTypeDefs = [typeDefs];
const allResolvers = [sdlResolvers, givenResolvers];
if (entityTypeNames.length > 0) {
allTypeDefs.push(`union _Entity = ${entityTypeNames.join(' | ')}`);
allTypeDefs.push(`extend type Query {
_entities(representations: [_Any!]!): [_Entity]!
}`);
allResolvers.push({
_Entity: {
__resolveType: entityTypeResolver,
},
Query: {
_entities: (_root, args, context, info) => value_or_promise_1.ValueOrPromise.all(args.representations.map(representation => new value_or_promise_1.ValueOrPromise(() => givenResolvers[representation.__typename]?.__resolveReference?.(representation, context, info)).then(resolvedEntity => {
if (!resolvedEntity) {
return representation;
}
if (!resolvedEntity.__typename) {
resolvedEntity.__typename = representation.__typename;
}
return resolvedEntity;
}))).resolve(),
},
});
}
return (0, schema_1.makeExecutableSchema)({
assumeValid: true,
assumeValidSDL: true,
...opts,
typeDefs: allTypeDefs,
resolvers: allResolvers,
});
}
exports.buildSubgraphSchema = buildSubgraphSchema;
function entityTypeResolver(obj) {
return obj.__typename;
}
const sdlResolvers = {
Query: {
_service: () => ({}),
},
_Service: {
sdl: (_root, _args, _context, info) => (0, utils_1.printSchemaWithDirectives)(info.schema),
},
};
;