Pass context into scalar coercing
See original GitHub issueMaking scalar coercion more powerful
It would be a huge advantage to be able to access the context during serializing/deserializing scalars. It would allow to reduce a lot of additional type conversion that must happen in data fetchers on input and output because it requires some contextual information.
Use cases:
Converting date time to client’s time zone
Some applications need to be aware of the current user time zone. This is for example necessary when aggregating calendar events into dates. It just cannot be done in UTC.
The application could internally work with java.time.Instant
. During the conversion from the literal to Java type the context object could provide the current client time-zone and convert it to the correct Instant
thus keeping the conversion logic in one place.
GraphQLScalarType
.newScalar()
.name("DateTime")
.coercing(new Coercing<Instant, String>() {
@Override
public String serialize(Object instant, Context context) {
if (instant instanceof Instant) {
((Instant) instant).atZone(context.getZoneId()).toString();
}
// throw
}
@Override
public Instant parseValue(Object input, Context context) {
LocalDateTime.parse(input).atZone(context.getZoneId).toInstant();
}
})
.build();
Translating strings into client’s locale
Similarly, Strings could be translated on output by using a special type internally MessageBundleKey
and converting it to GraphQL string in the coercion. By being able to access the context it would be possible to determine the client locale and translate the message bundle key type into GraphQL string in the correct language.
GraphQLScalarType
.newScalar()
.name("LocalizedString")
.coercing(new Coercing<MessageBundleKey, String>() {
@Override
public String serialize(Object key, Context context) {
return messageBundle.getMessage(key, context.getLocale());
}
})
.build();
Workaround
The only current workaround is to inject the context in a different way. For example using thread local global variables. Spring already offers a similar mechanism using the LocaleContextHolder
class. The disadvantage is that it relies on the fact that each thread has a separate context which is not true in a reactive app or when using subscriptions.
Issue Analytics
- State:
- Created 3 years ago
- Comments:6 (5 by maintainers)
I agree with this sentiment - the
Coercing
is a SPI and like theDataFetcher
SPI you need context for more extended cases.The original code was based on the graphql-js implementation and simple String/Int scalars do not need it. But as you say a DateTime based on the current callers Locale needs context.
The trick here would be migration to this. All the Scalars existing today do not expect a context (we would probably call it
ScalarEnvironment
to apeDataFetchingEnvironment
) and hence that MUST continueThat said we already have a example where we have done this
graphql.schema.Coercing#parseLiteral(java.lang.Object, java.util.Map<java.lang.String,java.lang.Object>)
which is defaulted on the interface. We would need to do the same
Lets leave this open UNTIL we merge that PR - its likely but not yet done