Handle subscriptions in wrapResolvers

This commit is contained in:
Convly 2021-09-29 13:35:26 +02:00
parent c1e3c41cbd
commit 96ac7e314b

View File

@ -30,88 +30,90 @@ const wrapResolvers = ({ schema, strapi, extension = {} }) => {
// Fields filters // Fields filters
const isValidFieldName = ([field]) => !field.startsWith('__'); const isValidFieldName = ([field]) => !field.startsWith('__');
const typeMap = schema.getTypeMap(); const typesMaps = [schema.getTypeMap(), schema.getSubscriptionType().getFields()];
// Iterate over every field from every type within the typesMaps.forEach(typeMap =>
// schema's type map and wrap its resolve attribute if needed // Iterate over every field from every type within the
Object.entries(typeMap).forEach(([type, definition]) => { // schema's type map and wrap its resolve attribute if needed
const isGraphQLObjectType = definition instanceof GraphQLObjectType; Object.entries(typeMap).forEach(([type, definition]) => {
const isIgnoredType = introspectionQueries.includes(type); const isGraphQLObjectType = definition instanceof GraphQLObjectType;
const isIgnoredType = introspectionQueries.includes(type);
if (!isGraphQLObjectType || isIgnoredType) { if (!isGraphQLObjectType || isIgnoredType) {
return; return;
} }
const fields = definition.getFields(); const fields = definition.getFields();
const fieldsToProcess = Object.entries(fields).filter(isValidFieldName); const fieldsToProcess = Object.entries(fields).filter(isValidFieldName);
for (const [fieldName, fieldDefinition] of fieldsToProcess) { for (const [fieldName, fieldDefinition] of fieldsToProcess) {
const defaultResolver = get(fieldName); const defaultResolver = get(fieldName);
const path = `${type}.${fieldName}`; const path = `${type}.${fieldName}`;
const resolverConfig = getOr({}, path, resolversConfig); const resolverConfig = getOr({}, path, resolversConfig);
const { resolve: baseResolver = defaultResolver } = fieldDefinition; const { resolve: baseResolver = defaultResolver } = fieldDefinition;
// Parse & initialize the middlewares // Parse & initialize the middlewares
const middlewares = parseMiddlewares(resolverConfig, strapi); const middlewares = parseMiddlewares(resolverConfig, strapi);
// Generate the policy middleware // Generate the policy middleware
const policyMiddleware = createPoliciesMiddleware(resolverConfig, { strapi }); const policyMiddleware = createPoliciesMiddleware(resolverConfig, { strapi });
// Add the policyMiddleware at the end of the middlewares collection // Add the policyMiddleware at the end of the middlewares collection
middlewares.push(policyMiddleware); middlewares.push(policyMiddleware);
// Bind every middleware to the next one // Bind every middleware to the next one
const boundMiddlewares = middlewares.map((middleware, index, collection) => { const boundMiddlewares = middlewares.map((middleware, index, collection) => {
return (...args) => return (...args) =>
middleware( middleware(
// Make sure the last middleware in the list calls the baseResolver // Make sure the last middleware in the list calls the baseResolver
index >= collection.length - 1 ? baseResolver : boundMiddlewares[index + 1], index >= collection.length - 1 ? baseResolver : boundMiddlewares[index + 1],
...args ...args
); );
}); });
/** /**
* GraphQL authorization flow * GraphQL authorization flow
* @param {object} context * @param {object} context
* @return {Promise<void>} * @return {Promise<void>}
*/ */
const authorize = async ({ context }) => { const authorize = async ({ context }) => {
const authConfig = get('auth', resolverConfig); const authConfig = get('auth', resolverConfig);
const authContext = get('state.auth', context); const authContext = get('state.auth', context);
const isMutationOrQuery = ['Mutation', 'Query'].includes(type); const isValidType = ['Mutation', 'Query', 'Subscription'].includes(type);
const hasConfig = !isNil(authConfig); const hasConfig = !isNil(authConfig);
const isAuthDisabled = authConfig === false; const isAuthDisabled = authConfig === false;
if ((isMutationOrQuery || hasConfig) && !isAuthDisabled) { if ((isValidType || hasConfig) && !isAuthDisabled) {
try { try {
await strapi.auth.verify(authContext, authConfig); await strapi.auth.verify(authContext, authConfig);
} catch (error) { } catch (error) {
// TODO: [v4] Throw GraphQL Error instead // TODO: [v4] Throw GraphQL Error instead
throw new Error('Forbidden access'); throw new Error('Forbidden access');
}
} }
} };
};
/** /**
* Base resolver wrapper that handles authorization, middlewares & policies * Base resolver wrapper that handles authorization, middlewares & policies
* @param {object} parent * @param {object} parent
* @param {object} args * @param {object} args
* @param {object} context * @param {object} context
* @param {object} info * @param {object} info
* @return {Promise<any>} * @return {Promise<any>}
*/ */
fieldDefinition.resolve = async (parent, args, context, info) => { fieldDefinition.resolve = async (parent, args, context, info) => {
await authorize({ context }); await authorize({ context });
// Execute middlewares (including the policy middleware which will always be included) // Execute middlewares (including the policy middleware which will always be included)
return first(boundMiddlewares).call(null, parent, args, context, info); return first(boundMiddlewares).call(null, parent, args, context, info);
}; };
} }
}); })
);
return schema; return schema;
}; };