apollographql / apollo-client

:rocket:  A fully-featured, production ready caching GraphQL client for every UI framework and GraphQL server.
https://apollographql.com/client
MIT License
19.38k stars 2.66k forks source link

expose `setErrorMessageHandler` #11694

Closed phryneas closed 8 months ago

phryneas commented 8 months ago

This would be an alternative solution to the concerns brought up in #11667 and #11655.

changeset-bot[bot] commented 8 months ago

🦋 Changeset detected

Latest commit: 5bc618869ca316638db50466e6aad2ff78f7c329

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package | Name | Type | | -------------- | ----- | | @apollo/client | Patch |

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

github-actions[bot] commented 8 months ago

size-limit report 📦

Path Size
dist/apollo-client.min.cjs 38.35 KB (0%)
import { ApolloClient, InMemoryCache, HttpLink } from "dist/main.cjs" 46.17 KB (0%)
import { ApolloClient, InMemoryCache, HttpLink } from "dist/main.cjs" (production) 43.73 KB (0%)
import { ApolloClient, InMemoryCache, HttpLink } from "dist/index.js" 33.95 KB (0%)
import { ApolloClient, InMemoryCache, HttpLink } from "dist/index.js" (production) 31.87 KB (0%)
import { ApolloProvider } from "dist/react/index.js" 1.23 KB (0%)
import { ApolloProvider } from "dist/react/index.js" (production) 1.22 KB (0%)
import { useQuery } from "dist/react/index.js" 5.26 KB (0%)
import { useQuery } from "dist/react/index.js" (production) 4.35 KB (0%)
import { useLazyQuery } from "dist/react/index.js" 5.5 KB (0%)
import { useLazyQuery } from "dist/react/index.js" (production) 4.58 KB (0%)
import { useMutation } from "dist/react/index.js" 3.51 KB (0%)
import { useMutation } from "dist/react/index.js" (production) 2.73 KB (0%)
import { useSubscription } from "dist/react/index.js" 3.19 KB (0%)
import { useSubscription } from "dist/react/index.js" (production) 2.38 KB (0%)
import { useSuspenseQuery } from "dist/react/index.js" 5.36 KB (0%)
import { useSuspenseQuery } from "dist/react/index.js" (production) 4.03 KB (0%)
import { useBackgroundQuery } from "dist/react/index.js" 4.83 KB (0%)
import { useBackgroundQuery } from "dist/react/index.js" (production) 3.49 KB (0%)
import { useLoadableQuery } from "dist/react/index.js" 4.98 KB (0%)
import { useLoadableQuery } from "dist/react/index.js" (production) 3.63 KB (0%)
import { useReadQuery } from "dist/react/index.js" 3.12 KB (0%)
import { useReadQuery } from "dist/react/index.js" (production) 3.06 KB (0%)
import { useFragment } from "dist/react/index.js" 2.27 KB (0%)
import { useFragment } from "dist/react/index.js" (production) 2.22 KB (0%)
netlify[bot] commented 8 months ago

Deploy Preview for apollo-client-docs ready!

Name Link
Latest commit 3d8b7aa6deffeef2357e427b86ac8e901a6086da
Latest deploy log https://app.netlify.com/sites/apollo-client-docs/deploys/65f95f83ef9e5e0008b18bb4
Deploy Preview https://deploy-preview-11694--apollo-client-docs.netlify.app
Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

netlify[bot] commented 8 months ago

Deploy Preview for apollo-client-docs ready!

Name Link
Latest commit 501873852423c44e60672e10f366bb86d6951d68
Latest deploy log https://app.netlify.com/sites/apollo-client-docs/deploys/65f97ffd1f749a00089c86b3
Deploy Preview https://deploy-preview-11694--apollo-client-docs.netlify.app
Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

phryneas commented 8 months ago

@iiroj Mentioning so you see this - it will give you full control over error messages and log messages.

This might, in the case of invariant.log etc. still log cache internals to the console (see the code comment on args), but will allow you to control the "url" behaviour that you want to avoid.

On top of that, you can control the logging of that using setVerbosity, so I hope these two things hand-in-hand should address all your concerns.

iiroj commented 8 months ago

@phryneas Thanks! I'm pretty sure this would allow me to override the message by supplying something like:

setErrorMessageHandler(() => "")

However, all of the code in the invariantWrappers.ts generates the error message like this, so any falsy values will fall through to the "fallback message":

getHandledErrorMsg(message, optionalParams) || getFallbackErrorMsg(message, optionalParams)

Also, since in the wrap function the final originalInvariant will be called with ...[message].concat(args), any customized message will still be followed by all the arguments (so basically the custom error message data).

I would expect setErrorMessageHandler(myHandler) to behave like this:

phryneas commented 8 months ago

@iiroj I have documented both of these behaviours in the ErrorMessageHandler type:

/**
   * @returns The error message to be logged or thrown. If it returns `undefined`,
   *          the mechanism will fall back to the default:
   *          A link to https://go.apollo.dev/c/err with Apollo Client version,
   *          the error message number, and the error message arguments encoded into
   *          the URL hash.
   */

=> Returning undefined is the way of saying "we don't have a known error message for this, handle it the default way". That's important for us because you can load some of the messages (e.g. only the dev messages, or only the errors) and we still have to handle the rest somehow.

/**
   * ⚠️ Note that arguments will only be passed in for error messages.
   * For normal log messages, you will get an empty array here and they will directly
   * be passed to `console.log` instead, to have the string subsitution done by the
   * engine, as that allows for nicer (and in the case of a browser, interactive)
   * output.
   */

This is something that's also kind of a tradeoff:
If we wouldn't send the arguments for invariant.log directly to console.log, but we'd inline them into the string, they couldn't be explored using the browser console, which would hurt the ability to interactively inspect/collapse/debug those values. We have to inline them in the error message, since JavaScript doesn't offer an "inspection" method like that for errors, though.

That said, invariant.debug/log/warn/error messages will never make it into the production build (assuming you have set that up correctly), so you should not have to worry about those in the first place.

(Take a look at the packaged JavaScript - a call to invariant.warn(e) would end up in our dist folder as globalThis.__DEV__ !== false && invariant.warn(e);, which would then be removed by your bundler in a prod build.)

In a production build, you'll only see InvariantErrors, and their messages are completely under your control.

If you even want to silence those logs in a development environment, completely (although I'd really recommend logging something!) you can still use ts-invariant's setVerbosity.