Skip to content

scalars with access to context re #2663 #3539

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

Closed
iambumblehead opened this issue Apr 21, 2022 · 6 comments
Closed

scalars with access to context re #2663 #3539

iambumblehead opened this issue Apr 21, 2022 · 6 comments

Comments

@iambumblehead
Copy link

I'd like my graphql service to return internationalized error messages for invalid scalars

Following the example from this related ticket #2663, I'd like the service to do something like this,

  parseValue: (value, context) => {
    const lang = context.get( 'accept-language' ); // somehow access express/koa language header
    const rounded = round(value);
    if (value !== rounded) {
      // throw new GraphQLError("Please provide a rounded number");
      throw new GraphQLError( i18nMessage( lang, 'please_provide_rounded_number' ) );
    }
    return value;
  },

Is there a known way to achieve the result described above? Because the scalar type does not have access to the context, I can't imagine how to achieve this.

@iambumblehead
Copy link
Author

iambumblehead commented Apr 21, 2022

related apollographql/apollo-server#4010

apollo documentation vaguely recommend a mixture of ineffective plugins and hooks that require a lot of boilerplate code

@saihaj
Copy link
Member

saihaj commented Apr 23, 2022

Yeah we don't really have a way to pass context to type system. You could try something with envelop and hijack the results on after hooks in lifecycle methods

@iambumblehead
Copy link
Author

context is widely needed and perhaps it should be passed through all parts of the response lifecycle, to be shared with any possible userland hooks that would need to modify or customize anything.

@IvanGoncharov
Copy link
Member

@iambumblehead Thanks for providing the code sample, it makes super clear what you want to achieve.
Sadly scalars are used in many situations where context is not available (e.g. default values in SDL, introspection, etc.).

You can solve your use case by using formatError (or similarly named) callback provided by your framework and extensions field.

  parseValue: (value, context) => {
    const rounded = round(value);
    if (value !== rounded) {
      throw new GraphQLError({
        message: "Please provide a rounded number",
        extensions: { i18nMessage: 'please_provide_rounded_number' },
      });
    }
    return value;
  },

For the server part, I will use https://github.com/graphql/express-graphql for this example, but almost every other popular GraphQL server allows the same.

app.use(
  '/graphql',
  graphqlHTTP(async (request, response, graphQLParams) => ({
    schema: MyGraphQLSchema,
    // ...
    customFormatErrorFn(error) {
      const formattedError = error.toJSON();
      
      const { i18nMessage } = error.extensions;
      if (i18nMessage != null) {
        const lang = request.headers['accept-language'];
        formattedError.message = i18nMessage(lang, i18nMessage);
      }
      return formattedError;
    }
  })),
);

Moreover, it's a generalized approach that allows you to provide internationalization for every error with passing context all around your code.
Plus you keep i18nMessage extension field in the server response which means better logging and debugging (since you can find similar errors without trying every language-specific message).

Does this solution solve your problem?

@iambumblehead
Copy link
Author

@IvanGoncharov thank you for the response. This solution is similar to the one I ultimately did end up using.

@yaacovCR
Copy link
Contributor

Great! Closing for housekeeping, please feel free to reopen as necessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants