Skip to content

Instantly share code, notes, and snippets.

@acomagu
Created February 5, 2022 11:40
Show Gist options
  • Save acomagu/813e188fa58055262691d368ff77c91d to your computer and use it in GitHub Desktop.
Save acomagu/813e188fa58055262691d368ff77c91d to your computer and use it in GitHub Desktop.
@auth(role: ...) GraphQL directive implementation in TypeScript.
import { mapSchema, getDirective, MapperKind } from '@graphql-tools/utils';
import { defaultFieldResolver, GraphQLError, GraphQLFieldResolver, GraphQLSchema } from 'graphql';
function wrapField<Field extends { resolve?: GraphQLFieldResolver<any, any> }>(field: Field, authDirective: Record<string, any>) {
const { resolve = defaultFieldResolver } = field;
field.resolve = (src, args, ctx, info) => {
if (ctx.role !== authDirective.role) throw new GraphQLError(`${authDirective.role} role is needed but your role is ${ctx.role}.`);
return resolve(src, args, ctx, info);
};
return field;
}
// Collate "role" field in the context with the @auth directive in resolving.
//
// Expected directive definition:
// `directive @auth(role: Role!) on FIELD_DEFINITION | OBJECT`
export function authDirectiveTransformer(schema: GraphQLSchema) {
return mapSchema(schema, {
[MapperKind.OBJECT_FIELD]: (fieldConfig) => {
const authDirective = getDirective(schema, fieldConfig, 'auth')?.[0];
if (!authDirective) return;
return wrapField(fieldConfig, authDirective);
},
[MapperKind.OBJECT_TYPE]: (type) => {
const authDirective = getDirective(schema, type, 'auth')?.[0];
if (!authDirective) return;
const fields = type.getFields();
for (const name of Object.keys(fields)) {
fields[name] = wrapField(fields[name], authDirective);
}
return type;
},
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment