I wondering if it is possible to automatically enforce GraphQL directive in Spring GraphQL.
My schema is
directive @validateUserId on ARGUMENT_DEFINITION
type Mutation {
addBook(userId: ID! @validateUserId , name:String, pageCount:Int, author:NewAuthorInput): Book
}
Mutation handler in my controller:
@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);
}
and my directive wiring:
@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
}
}
In this code I explicitly calling ValidateUserIdDirective.validateUserId(environment);
in my mutation handler. I am wondering if there is a way to automatically validate user directive without making any explicit calls?
I wondering if it is possible to automatically enforce GraphQL directive in Spring GraphQL.
My schema is
directive @validateUserId on ARGUMENT_DEFINITION
type Mutation {
addBook(userId: ID! @validateUserId , name:String, pageCount:Int, author:NewAuthorInput): Book
}
Mutation handler in my controller:
@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);
}
and my directive wiring:
@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
}
}
In this code I explicitly calling ValidateUserIdDirective.validateUserId(environment);
in my mutation handler. I am wondering if there is a way to automatically validate user directive without making any explicit calls?
2 Answers
Reset to default 0Instead of manually calling ValidateUserIdDirective.validateUserId(environment)
in your @MutationMapping method
, you can modify your ValidateUserIdDirective
to intercept the DataFetcher
for the field and apply the validation logic automatically.
This is done by wiring the directive at the schema level and modifying the DataFetcher
behavior.
import graphql.schema.*;
import .springframework.graphql.execution.SchemaDirectiveWiring;
import .springframework.stereotype.Component;
import graphql.schema.idl.SchemaDirectiveWiringEnvironment;
import java.util.Objects;
import java.util.UUID;
@Component
public class ValidateUserIdDirective implements SchemaDirectiveWiring {
@Override
public GraphQLArgument onArgument(SchemaDirectiveWiringEnvironment<GraphQLArgument> environment) {
GraphQLArgument argument = environment.getElement();
GraphQLFieldDefinition field = environment.getFieldDefinition();
DataFetcher<?> originalDataFetcher = environment.getCodeRegistry().getDataFetcher(
(GraphQLObjectType) field.getParentType(), field);
DataFetcher<?> wrappedDataFetcher = dataFetchingEnvironment -> {
String userIdArg = dataFetchingEnvironment.getArgument("userId");
validateUserId(userIdArg);
return originalDataFetcher.get(dataFetchingEnvironment);
};
// Register the wrapped DataFetcher in the CodeRegistry
environment.getCodeRegistry().dataFetcher(
(GraphQLObjectType) field.getParentType(), field, wrappedDataFetcher);
return argument;
}
private void validateUserId(String userId) {
UUID providedUserId = UUID.fromString(Objects.requireNonNull(userId));
// Add your validation logic here
System.out.println("Validated userId: " + providedUserId);
}
}
I solved the problem by correct registration of my wiring directive:
@Bean
public RuntimeWiringConfigurer runtimeWiringConfigurer(ValidateUserIdDirective validateUserIdDirective) {
return wiringBuilder -> wiringBuilder
.directive("validateUserId", validateUserIdDirective);
}