graphql
graphql copied to clipboard
Applying Field Metadata Outside Of `@Field()` Decorator
In the GraphQL extension docs, there's an extensions middleware:
@Field({ middleware: [checkRoleMiddleware] })
@Extensions({ role: Role.ADMIN })
password: string;
As cool as this is, I'd like to add extensions & middleware field via applyDecorator to both @Field() and @ResolveField() fields.
@Field()
@Auth(Role.ADMIN)
password: string;
// and use same extension decorator with field resolvers
@ResolveField()
@Auth(Role.ADMIN)
somethingPrivate(): string {
// ...
}
I currently use extensions & transformSchema to apply graphql-shield (since guards don't work on ResolveField). I think being able to add field middleware through a decorator would be more ideal and flexible:
export function Auth(...roles: string[]) {
return applyDecorators(
ApplyMiddleware(checkRoleMiddleware),
SetMetadata('roles', roles),
Extensions({ roles })
);
}
There are of course alternative ways of doing this using extensions:
- Create a directive to visit all fields of the schema and modify their resolver if it contains the directive (essentially applying a "middleware").
- Use
transformSchemalike I did above to modify field resolvers which contain given metadata (pretty much very similar as 1st option.
The problem with these is that I can't create a module to ensure it's set up correctly. I have to create steps for users to follow to make this work correctly. I see ApplyMiddleware type of decorator being the best option unless we support registering directives and/or transformSchema functions outside of the user's GraphQL module:
@RegisterDirective()
export class AuthDirective extends SchemaDirectiveVisitor {
// ...
}
// or
@TransformSchema()
export class AuthTransformSchema implements SchemaTransformer {
constructor(private readonly authService: AuthService) {}
async transform(schema: GraphQLSchema): Promise<schema> {
// find fields with auth extensions and do some magic
// return modified schema
return schema;
}
}
Not sure if I'm following.
As cool as this is, I'd like to add extensions & middleware field via applyDecorator to both @Field() and @ResolveField() fields.
I think this should be doable by checking the target (whether it's a property or method) and applying the appropriate decorator.
@kamilmysliwiec I mean that I want to use applyDecorator to apply both extensions and field middleware to an existing field. Right now I'd have to not use @Field() and instead create a decorator like, @AuthField(). Mainly I'm talking about the ability to apply "middleware" to an already existing @Field().