X Tutup
Skip to content

Pass context into scalar coercing #1893

@vojtapol

Description

@vojtapol

Making 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      X Tutup