179 lines
5.4 KiB
TypeScript
179 lines
5.4 KiB
TypeScript
import * as GraphQL from 'graphql';
|
|
import { GraphQLError, GraphQLFormattedError, GraphQLObjectType, GraphQLSchema } from 'graphql';
|
|
import { graphqlHTTP } from 'express-graphql';
|
|
import queryComplexity, { simpleEstimator, fieldExtensionsEstimator } from 'graphql-query-complexity';
|
|
import buildObjectType from './schema/buildObjectType';
|
|
import buildMutationInputType from './schema/buildMutationInputType';
|
|
import errorHandler from './errorHandler';
|
|
import buildBlockType from './schema/buildBlockType';
|
|
import buildPoliciesType from './schema/buildPoliciesType';
|
|
import buildLocaleInputType from './schema/buildLocaleInputType';
|
|
import buildFallbackLocaleInputType from './schema/buildFallbackLocaleInputType';
|
|
import initCollections from '../collections/graphql/init';
|
|
import initGlobals from '../globals/graphql/init';
|
|
import initPreferences from '../preferences/graphql/init';
|
|
import { GraphQLResolvers } from './bindResolvers';
|
|
import buildVersionType from './schema/buildVersionType';
|
|
import buildWhereInputType from './schema/buildWhereInputType';
|
|
import { SanitizedConfig } from '../config/types';
|
|
|
|
type GraphQLTypes = {
|
|
blockTypes: any;
|
|
blockInputTypes: any;
|
|
localeInputType: any;
|
|
fallbackLocaleInputType: any;
|
|
}
|
|
|
|
class InitializeGraphQL {
|
|
types: GraphQLTypes;
|
|
|
|
config: SanitizedConfig;
|
|
|
|
graphQL: {
|
|
resolvers: GraphQLResolvers
|
|
};
|
|
|
|
Query: { name: string; fields: { [key: string]: any } } = { name: 'Query', fields: {} };
|
|
|
|
Mutation: { name: string; fields: { [key: string]: any } } = { name: 'Mutation', fields: {} };
|
|
|
|
buildBlockType: typeof buildBlockType;
|
|
|
|
buildMutationInputType: typeof buildMutationInputType;
|
|
|
|
buildWhereInputType: (name: any, fields: any, parentName: any) => GraphQL.GraphQLInputObjectType;
|
|
|
|
buildObjectType: typeof buildObjectType;
|
|
|
|
buildPoliciesType: typeof buildPoliciesType;
|
|
|
|
buildVersionType: typeof buildVersionType;
|
|
|
|
initCollections: typeof initCollections;
|
|
|
|
initGlobals: typeof initGlobals;
|
|
|
|
initPreferences: typeof initPreferences;
|
|
|
|
schema: GraphQL.GraphQLSchema;
|
|
|
|
extensions: (info: any) => Promise<any>;
|
|
|
|
customFormatErrorFn: (error: GraphQLError) => GraphQLFormattedError;
|
|
|
|
validationRules: any;
|
|
|
|
errorResponse: any;
|
|
|
|
constructor(init) {
|
|
Object.assign(this, init);
|
|
this.init = this.init.bind(this);
|
|
|
|
this.types = {
|
|
blockTypes: {},
|
|
blockInputTypes: {},
|
|
} as GraphQLTypes;
|
|
|
|
if (this.config.localization) {
|
|
this.types.localeInputType = buildLocaleInputType(this.config.localization);
|
|
this.types.fallbackLocaleInputType = buildFallbackLocaleInputType(this.config.localization);
|
|
}
|
|
|
|
this.Query = {
|
|
name: 'Query',
|
|
fields: {},
|
|
};
|
|
this.Mutation = {
|
|
name: 'Mutation',
|
|
fields: {},
|
|
};
|
|
|
|
this.buildBlockType = buildBlockType.bind(this);
|
|
this.buildMutationInputType = buildMutationInputType.bind(this);
|
|
this.buildWhereInputType = buildWhereInputType;
|
|
this.buildObjectType = buildObjectType.bind(this);
|
|
this.buildPoliciesType = buildPoliciesType.bind(this);
|
|
this.buildVersionType = buildVersionType.bind(this);
|
|
this.initCollections = initCollections.bind(this);
|
|
this.initGlobals = initGlobals.bind(this);
|
|
this.initPreferences = initPreferences.bind(this);
|
|
|
|
this.initCollections();
|
|
this.initGlobals();
|
|
this.initPreferences();
|
|
|
|
this.Query.fields.Access = {
|
|
type: this.buildPoliciesType(),
|
|
resolve: this.graphQL.resolvers.collections.auth.access,
|
|
};
|
|
|
|
if (typeof this.config.graphQL.queries === 'function') {
|
|
const customQueries = this.config.graphQL.queries(GraphQL, init);
|
|
this.Query = {
|
|
...this.Query,
|
|
fields: {
|
|
...this.Query.fields,
|
|
...(customQueries || {}),
|
|
},
|
|
};
|
|
}
|
|
|
|
if (typeof this.config.graphQL.mutations === 'function') {
|
|
const customMutations = this.config.graphQL.mutations(GraphQL, init);
|
|
this.Mutation = {
|
|
...this.Mutation,
|
|
fields: {
|
|
...this.Mutation.fields,
|
|
...(customMutations || {}),
|
|
},
|
|
};
|
|
}
|
|
|
|
const query = new GraphQLObjectType(this.Query);
|
|
const mutation = new GraphQLObjectType(this.Mutation);
|
|
|
|
const schema = {
|
|
query,
|
|
mutation,
|
|
};
|
|
|
|
this.schema = new GraphQLSchema(schema);
|
|
|
|
this.extensions = async (info) => {
|
|
const { result } = info;
|
|
if (result.errors) {
|
|
const afterErrorHook = typeof this.config.hooks.afterError === 'function' ? this.config.hooks.afterError : null;
|
|
[this.errorResponse] = await errorHandler(info, this.config.debug, afterErrorHook);
|
|
}
|
|
return null;
|
|
};
|
|
this.customFormatErrorFn = (error) => (this.errorResponse || error);
|
|
this.validationRules = (variables) => ([
|
|
queryComplexity({
|
|
estimators: [
|
|
fieldExtensionsEstimator(),
|
|
simpleEstimator({ defaultComplexity: 1 }), // Fallback if complexity not set
|
|
],
|
|
maximumComplexity: this.config.graphQL.maxComplexity,
|
|
variables,
|
|
// onComplete: (complexity) => { console.log('Query Complexity:', complexity); },
|
|
}),
|
|
]);
|
|
}
|
|
|
|
init(req, res) {
|
|
this.errorResponse = null;
|
|
return graphqlHTTP(
|
|
async (request, response, { variables }) => ({
|
|
schema: this.schema,
|
|
customFormatErrorFn: this.customFormatErrorFn,
|
|
extensions: this.extensions,
|
|
context: { req, res },
|
|
validationRules: this.validationRules(variables),
|
|
}),
|
|
);
|
|
}
|
|
}
|
|
|
|
export default InitializeGraphQL;
|