如何在Spring GraphQL中自动执行@validateUserId指令?
Spring GraphQL 自动执行自定义@validateUserId指令
问题背景
当前定义了@validateUserId指令用于验证Mutation参数中的userId,但需要在处理器方法里显式调用ValidateUserIdDirective.validateUserId(environment)才能执行验证,希望实现无需手动调用、自动触发的验证逻辑。
相关代码如下:
Schema定义
directive @validateUserId on ARGUMENT_DEFINITION type Mutation { addBook(userId: ID! @validateUserId , name:String, pageCount:Int, author:NewAuthorInput): Book }
Mutation处理器代码
@MutationMapping public Book addBook(@Argument UUID userId, @Argument String name, @Argument Integer pageCount, @NotNull @Argument NewAuthorInput author, DataFetchingEnvironment environment) { ValidateUserIdDirective.validateUserId(environment); Author newAuthor = bookService.addAuthor(author.getFirstName(), author.getLastName()); return bookService.addBook(name, pageCount, newAuthor); }
指令实现代码
@Component public class ValidateUserIdDirective implements SchemaDirectiveWiring { @Override public GraphQLArgument onArgument(SchemaDirectiveWiringEnvironment<GraphQLArgument> environment) { return environment.getElement(); } public static void validateUserId(DataFetchingEnvironment environment) { UUID providedUserId = UUID.fromString(Objects.requireNonNull(environment.getArgument("userId"))); // do something with user id } }
解决方案
可以通过**包装数据获取器(DataFetcher)**的方式,在SchemaDirectiveWiring的实现中注入验证逻辑,让指令自动触发验证,无需手动调用。具体修改如下:
修改指令实现类
@Component public class ValidateUserIdDirective implements SchemaDirectiveWiring { @Override public GraphQLArgument onArgument(SchemaDirectiveWiringEnvironment<GraphQLArgument> environment) { // 获取当前参数所属的Mutation字段 GraphQLFieldDefinition fieldDefinition = environment.getFieldDefinition(); // 拿到原有的业务处理DataFetcher DataFetcher<?> originalFetcher = environment.getCodeRegistry().getDataFetcher(fieldDefinition); // 包装原DataFetcher,添加前置验证逻辑 DataFetcher<?> wrappedFetcher = dataFetchingEnv -> { // 提取并验证userId参数 UUID providedUserId = UUID.fromString(Objects.requireNonNull(dataFetchingEnv.getArgument("userId"))); // 这里编写具体验证逻辑,比如检查用户是否存在、权限是否合法等 // 验证失败时可抛出GraphQLError终止请求,示例: // if (!userRepository.existsById(providedUserId)) { // throw new GraphqlErrorException(GraphqlErrorBuilder.newError() // .message("Invalid user ID: " + providedUserId) // .build()); // } // 验证通过后执行原业务逻辑 return originalFetcher.get(dataFetchingEnv); }; // 将包装后的DataFetcher注册回代码注册表 environment.getCodeRegistry().dataFetcher(fieldDefinition, wrappedFetcher); return environment.getElement(); } }
简化处理器代码
现在可以移除显式调用的验证方法,处理器代码简化为:
@MutationMapping public Book addBook(@Argument UUID userId, @Argument String name, @Argument Integer pageCount, @NotNull @Argument NewAuthorInput author) { Author newAuthor = bookService.addAuthor(author.getFirstName(), author.getLastName()); return bookService.addBook(name, pageCount, newAuthor); }
原理说明
SchemaDirectiveWiring的onArgument方法会在Schema构建阶段被触发,此时可以对目标字段的DataFetcher进行包装,在原业务逻辑执行前自动插入验证逻辑。当客户端发起对应的Mutation请求时,GraphQL引擎会先执行注入的验证代码,验证通过后才会调用处理器的业务方法,完全无需手动触发。
内容的提问来源于stack exchange,提问作者MrkK
相关产品推荐
相关产品推荐

