-
Notifications
You must be signed in to change notification settings - Fork 299
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Customize scalar type serialization #413
Comments
@benneq, GraphQL Java has support for scalar types. Have you tried it? This is also mentioned in the Spring for GraphQL reference docs. |
@rstoyanchev Thanks for the response 😸 (Btw: Great docs and Spring YouTube Series 👍 ) @QueryMapping
Mono<BookId> bookById(@Argument BookId id) {
return Mono.just(id);
}
// this will convert the returned MyCustomId (from ID Scalar Corercing parseValue and parseLiteral) to BookId
// so it can be used as @Argument in @QueryMapping
@Bean
Converter<MyCustomId, BookId> myConverter() {
return new Converter<MyCustomId, BookId>() {
@Override
public BookId convert(MyCustomId source) {
return new BookId(/* convert from MyCustomId */);
}
};
}
// Scalar ID Coercing serialize method is used to convert BookId to String
@Bean
RuntimeWiringConfigurer configurer() {
return builder -> builder.scalar(GraphQLScalarType.newScalar().name("ID").coercing(new Coercing<>() {
@Override
public String serialize(Object dataFetcherResult) {
if (dataFetcherResult instanceof BookId bookId) {
// custom BookId serialization code
return "Book:" + bookId.value();
}
throw new CoercingSerializeException();
}
@Override
public MyCustomId parseValue(Object input) {
if (input instanceof String) {
return new MyCustomId(/* parse input */);
}
throw new CoercingParseValueException();
}
@Override
public MyCustomId parseLiteral(Object input) {
if (input instanceof StringValue stringValue) {
// parse input to intermediate object, because at this point
// we have no information about the @Argument type
return new MyCustomId(/* parse input */);
}
throw new CoercingParseLiteralException();
}
};
} It's working fine. My only "issue" is that it's a lot of code and feels a bit strange to have the (de)serialization logic in two completely different places. If this is the intended way to do this, you can close this issue. |
@benneq it's not very clear why you need to have both a Spring |
@rstoyanchev I'll try to explain it in more detail: In my GraphQL schema I only have a single interface Node {
id: ID!
}
type Book implements Node {
id: ID!
}
type Author implements Node {
id: ID!
}
type Query {
node(id: ID!): Node
book(id: ID!): Book
author(id: ID!): Author
} Those I have a @Controller
public class BookController {
@QueryMapping
Mono<Book> book(@Argument BookId id) {
return Mono.just(new Book(...));
}
} The provided default Within the scalar coercing code this can not be done, because there (in the And the next issue is the @Controller
public class BookController {
@QueryMapping
Mono<BookId> someBookId() {
return Mono.just(new BookId(...));
}
} The provided default This conversion can not be done using Spring That's why I have used both, a custom scalar impl and a Converter. The Converter is used for custom |
Currently it's very hard to use custom Value Objects with ID Scalars. Or in general: to provide custom serialization for any kind of generics / class inheritance.
Schema:
Controller:
As a workaround I could implement a custom
BookId
scalar, with a matching scalar coercing, but this will lead to new problems:Another workaround would be to use
RuntimeWiringConfigurer
and override the defaultID
scalar and provide a customserialize
implementation that doesn't usetoString()
. But that's hard to use, especially if you want to dynamically provide new classes with custom serialization.The code in
graphql.execution.ExecutionStrategy
does not seem to provide a way to customize the serialization. Or maybe I have missed something in the code or the docs.Is there already a (easy) way to do this?
The text was updated successfully, but these errors were encountered: