Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
}
: null,
)
.filter(isNotNullOrUndefined);
keyDirectiveInfoOnTypeExtensions.push(...keyDirectivesInfo);
},
});
// this allows us to build a partial schema
let schema = new GraphQLSchema({
query: undefined,
directives: [...specifiedDirectives, ...federationDirectives],
});
try {
schema = buildSchemaFromSDL(typeDefs, schema);
} catch (e) {
errors.push(e);
return errors;
}
const typeInfo = new TypeInfo(schema);
for (const { typeName, keyArgument } of keyDirectiveInfoOnTypeExtensions) {
const keyDirectiveSelectionSet = parse(
`fragment __generated on ${typeName} { ${keyArgument} }`,
);
visit(
keyDirectiveSelectionSet,
visitWithTypeInfo(typeInfo, {
Field() {
const fieldDef = typeInfo.getFieldDef();
.join('\n')}`,
);
const { schema, errors } = composeAndValidate(serviceList);
if (errors && errors.length > 0) {
if (this.experimental_didFailComposition) {
this.experimental_didFailComposition({
errors,
serviceList,
...(this.compositionMetadata && {
compositionMetadata: this.compositionMetadata,
}),
});
}
throw new GraphQLSchemaValidationError(errors);
}
this.createServices(serviceList);
this.logger.debug('Schema loaded and ready for execution');
// this is a temporary workaround for GraphQLFieldExtensions automatic
// wrapping of all fields when using ApolloServer. Here we wrap all fields
// with support for resolving aliases as part of the root value which
// happens because alises are resolved by sub services and the shape
// of the rootvalue already contains the aliased fields as responseNames
return wrapSchemaWithAliasResolver(schema);
}
if (!schema.getQueryType()) {
schema = new GraphQLSchema({
...schema.toConfig(),
query: new GraphQLObjectType({
name: 'Query',
fields: {},
}),
});
}
const entityTypes = Object.values(schema.getTypeMap()).filter(
type => isObjectType(type) && typeIncludesDirective(type, 'key'),
);
const hasEntities = entityTypes.length > 0;
schema = transformSchema(schema, type => {
// Add `_entities` and `_service` fields to query root type
if (isObjectType(type) && type === schema.getQueryType()) {
const config = type.toConfig();
return new GraphQLObjectType({
...config,
fields: {
...(hasEntities && { _entities: entitiesField }),
_service: {
...serviceField,
resolve: () => ({ sdl }),
},
...config.fields,
},
});
}
Object.entries(federationConfig)
.filter(([, { keyFields }]) => keyFields && keyFields.length)
.map(([objectName]) => {
const type = schemaWithQueryType.getType(objectName);
if (!isObjectType(type)) {
throw new Error(
`Type "${objectName}" is not an object type and can't have a key directive`,
);
}
return [objectName, type];
}),
);
const hasEntities = !!Object.keys(entityTypes).length;
const schemaWithFederationQueryType = transformSchema(
schemaWithQueryType,
type => {
// Add `_entities` and `_service` fields to query root type
if (isObjectType(type) && type === schemaWithQueryType.getQueryType()) {
const config = type.toConfig();
return new GraphQLObjectType({
...config,
fields: {
...config.fields,
...(hasEntities && { _entities: entitiesField }),
_service: {
...serviceField,
resolve: () => ({ sdl: schemaWithFederationDirectives }),
},
},
});
};
schema = new GraphQLSchema({
...schema.toConfig(),
...mapValues(operationTypeMap, typeName =>
typeName
? (schema.getType(typeName) as GraphQLObjectType)
: undefined,
),
});
// If multiple type definitions and extensions for the same type implement the
// same interface, it will get added to the constructed object multiple times,
// resulting in a schema validation error. We therefore need to remove
// duplicate interfaces from object types manually.
schema = transformSchema(schema, type => {
if (isObjectType(type)) {
const config = type.toConfig();
return new GraphQLObjectType({
...config,
interfaces: Array.from(new Set(config.interfaces)),
});
}
return undefined;
});
addFederationMetadataToSchemaNodes({
schema,
typeToServiceMap,
externalFields,
keyDirectivesMap,
valueTypes,
...config,
fields: {
...config.fields,
...(hasEntities && { _entities: entitiesField }),
_service: {
...serviceField,
resolve: () => ({ sdl: schemaWithFederationDirectives }),
},
},
});
}
return undefined;
},
);
const schemaWithUnionType = transformSchema(
schemaWithFederationQueryType,
type => {
if (isUnionType(type) && type.name === EntityType.name) {
return new GraphQLUnionType({
...EntityType.toConfig(),
types: Object.values(entityTypes),
});
}
return undefined;
},
);
// Not using transformSchema since it will remove resolveReference
Object.entries(federationConfig).forEach(
([objectName, currentFederationConfig]) => {
if (currentFederationConfig.resolveReference) {
if ('typeDefs' in modulesOrSDL) {
const { typeDefs, resolvers } = modulesOrSDL;
const augmentedTypeDefs = Array.isArray(typeDefs) ? typeDefs : [typeDefs];
shapedModulesOrSDL = augmentedTypeDefs.map((typeDefs, i) => {
const module: GraphQLSchemaModule = { typeDefs };
// add the resolvers to the first "module" in the array
if (i === 0 && resolvers) module.resolvers = resolvers;
return module;
});
} else {
shapedModulesOrSDL = modulesOrSDL;
}
const modules = modulesFromSDL(shapedModulesOrSDL);
let schema = buildSchemaFromSDL(
modules,
new GraphQLSchema({
query: undefined,
directives: [...specifiedDirectives, ...federationDirectives],
}),
);
// At this point in time, we have a schema to be printed into SDL which is
// representative of what the user defined for their schema. This is before
// we process any of the federation directives and add custom federation types
// so its the right place to create our service definition sdl.
//
// We have to use a modified printSchema from graphql-js which includes
// support for preserving the *uses* of federation directives while removing
// their *definitions* from the sdl.
const sdl = printSchema(schema);
// load each path and get sdl string from each, if a list, concatenate them all
const documents = path
? [this.loadFileAndGetDocument(path)]
: paths
? paths.map(this.loadFileAndGetDocument, this)
: undefined;
if (!documents)
throw new Error(
`Schema could not be loaded for [${
path ? path : paths ? paths.join(", ") : "undefined"
}]`
);
this.schema = buildSchemaFromSDL(documents);
if (!this.schema) throw new Error(`Schema could not be loaded for ${path}`);
return this.schema;
}
([operationName, operationAST]) => {
const printed = defaultOperationRegistrySignature(
operationAST,
operationName
);
return {
signature: operationHash(printed),
document: printed,
// TODO: unused. Remove or repurpose this field altogether with op. registry 2.0 work.
// For now, this field is non-nullable on the input type.
metadata: {
engineSignature: ""
}
};
}
);
([operationName, operationAST]) => {
const printed = defaultOperationRegistrySignature(
operationAST,
operationName
);
return {
signature: operationHash(printed),
document: printed,
// TODO: unused. Remove or repurpose this field altogether with op. registry 2.0 work.
// For now, this field is non-nullable on the input type.
metadata: {
engineSignature: ""
}
};
}
);