<p>apollo-link-error renvoie l'erreur à l'appelant</p>

Créé le 15 avr. 2019  ·  17Commentaires  ·  Source: apollographql/apollo-link

J'utilise donc Apollo-link-error pour gérer les erreurs globales d'authentification et d'administration. Mais si je l'utilise, mes méthodes catch dans mes promesses ne renvoient pas les erreurs.

Il semble que toutes les erreurs passent par apollo-link-error et qu'elles ne soient pas renvoyées à la méthode de l'appelant.

Existe-t-il un moyen de renvoyer l'erreur à l'appelant afin que je puisse gérer certaines erreurs localement et certaines erreurs globalement ?

Commentaire le plus utile

J'ai trouvé la solution, un peu bizarre, mais c'est :

Cela imprime juste le message

  updateProfile: function() {
      this.$apollo
        .mutate({
          mutation: UPDATE_PROFILE,
          variables: current_user
        })
        .catch((error) => {
          console.log("this prints just the message", error);
        });
    }

MAIS cela imprime le contenu complet des erreurs

  updateProfile: function() {
      this.$apollo
        .mutate({
          mutation: UPDATE_PROFILE,
          variables: current_user
        })
        .catch(({ graphQLErrors }) => {
          console.log("this prints the full content of 'errors'", graphQLErrors);
        });
    }

Je pense que ce sujet peut être clos
@Nosherwan @romucci @Sceat @lbrdar

Tous les 17 commentaires

J'ai le même problème dans mon application. Je souhaite détecter toutes les erreurs dans le lien d'erreur (par exemple, pour pouvoir les enregistrer), mais je souhaite également les transmettre à l'appelant d'origine et les gérer là-bas, car elles peuvent contenir un message d'erreur personnalisé qui doit être affiché à l'utilisateur .

Mon code :

  • chez le fournisseur :
const errorLink = onError(({ graphQLErrors, networkError }) => {
  if (graphQLErrors) {
    graphQLErrors.forEach(({ message, locations, path }) => {
        console.log(`[GraphQL error]: ${message}, Location: ${locations}, Path: ${path}`);
      },
    );
  }
});

const client = new ApolloClient({
  link: authLink.concat(errorLink).concat(httpLink),
  cache: new InMemoryCache(),
});

  • en composant :
 loginMutation({ variables: { data } })
    .then(({ data, errors }) => {
      if (errors) {
        // I WANT TO BE ABLE TO READ ERROR MESSAGE HERE SO I CAN DISPLAY IT TO THE USER
      } else if (data) {
        ....
      }
    });

Notez qu'appeler forward n'aidera pas car il retourne undefined comme argument à then donc je n'aurais ni données ni erreur et définir errors à null n'est pas non plus une option car j'ai en fait besoin de lire les erreurs.

@lbrdar Avez-vous trouvé une solution de contournement pour cela?

Non

@lbrdar La façon de le faire n'est-elle pas avec une prise ?

 loginMutation({ variables: { data } })
    .then(({ data, errors }) => {
      if (errors) {
        // I WANT TO BE ABLE TO READ ERROR MESSAGE HERE SO I CAN DISPLAY IT TO THE USER
      } else if (data) {
        ....
      }
    }).catch(errors => {

    });

@lbrdar @romucci Je suis confronté au même problème. Avez-vous fini par résoudre ce problème ?

@Nosherwan Je viens d'installer la version 1.1.11 et tout fonctionne bien maintenant... Vous pouvez également vérifier vos promesses intérieures (peut-être que quelque part vous avez oublié de retourner une promesse dans une autre promesse)

@merksam merci pour le commentaire.
J'utilise exactement la même version que toi. Malheureusement, le comportement est le même.

const errorLink = onError(({ graphQLErrors, networkError }) => {
  if (graphQLErrors) {
    graphQLErrors.forEach(({ message, locations, path }) => {
        console.log(`[GraphQL error]: ${message}, Location: ${locations}, Path: ${path}`);
      },
    );
  }
});

Dans le bloc de code ci-dessus, les graphQLErrors sont interceptés et quelque chose peut être fait dans le gestionnaire onError. Cependant, ces erreurs ne sont pas transmises à la promesse d'appel réelle.
J'utilise des fonctions asynchrones, donc au lieu de 'then', j'utilise le mot-clé wait, et c'est à l'intérieur d'un bloc try catch.
le bloc catch intercepte l'erreur, mais aucune erreur ne lui est transmise.

Quelqu'un a-t-il trouvé une solution de contournement pour cela?

@Nosherwan @prem-prakash Pourrions-nous contacter quelque part dans le chat ou même passer un appel pour essayer de savoir pourquoi cela fonctionne dans mon cas et pas dans le vôtre ? (si c'est toujours d'actualité)

J'ai trouvé la solution, un peu bizarre, mais c'est :

Cela imprime juste le message

  updateProfile: function() {
      this.$apollo
        .mutate({
          mutation: UPDATE_PROFILE,
          variables: current_user
        })
        .catch((error) => {
          console.log("this prints just the message", error);
        });
    }

MAIS cela imprime le contenu complet des erreurs

  updateProfile: function() {
      this.$apollo
        .mutate({
          mutation: UPDATE_PROFILE,
          variables: current_user
        })
        .catch(({ graphQLErrors }) => {
          console.log("this prints the full content of 'errors'", graphQLErrors);
        });
    }

Je pense que ce sujet peut être clos
@Nosherwan @romucci @Sceat @lbrdar

Et si on ajoutait ça à la documentation ?

Désolé mais la solution ci-dessus ne fonctionne pas. Je suppose un exemple complet sur la façon de renvoyer les graphqlErrors en erreur de lien à l'appelant initial.

Dans mon cas, lorsqu'il y a une erreur, l'objet ApolloQueryResult suivant n'obtient pas les détails de l'erreur consolés dans le onError. Certains dans l'essai... attrapent autour de l'appel. Impossible d'obtenir les détails de graphqlError du serveur. Juste une "erreur 400"..

const gqlResult: ApolloQueryResult<IGReturnData<
            IAllDataTypes
        >> = await apolloClient.query<IGReturnData<IAllDataTypes>, TVariables>({
            query: queryGql,
            variables: queryVariables,
            errorPolicy: "all",
        });

configuration du serveur :

const errorLink = onError(({ graphQLErrors, networkError }) => {
    if (graphQLErrors)
        graphQLErrors.forEach(({ message, locations, path }) =>
            console.log(
                `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`,
            ),
        );

    if (networkError) console.log(`[Network error]: ${networkError}`);
});

const httplink = new HttpLink({
    uri: "/graphql",
    credentials: "include",
});

const links = [errorLink, httplink];

export const apolloClient = new ApolloClient({
    link: ApolloLink.from(links),
    cache: new InMemoryCache({ addTypename: false, fragmentMatcher }),
});

@prem-prakash merci.... sauveur..

Ce problème est extrêmement persistant. Je n'ai aucun contrôle sur le serveur graphql de mon projet, uniquement sur le client. Le serveur répond avec des erreurs graphql dans la forme correcte, mais avec un code d'état 400. Dans le lien d'erreur, j'ai accès à graphQLErrors , mais dans la mutation de composant, lorsque je sors graphQLErrors comme suggéré par @prem-prakash, graphQLErrors est un tableau vide . Je ne peux accéder qu'à un message par défaut « Erreur : Erreur réseau : Réponse non réussie : Code d'état reçu 400 ». Apollo écrase la messagerie d'erreur lisible par l'homme du serveur ("utilisateur ou mot de passe incorrect") parce que le code d'état 400 est un point pour Apollo.

Y a-t-il quelqu'un capable de gérer avec succès une réponse de code d'état 400 avec une messagerie d'erreur et de transmettre cette messagerie à l'interface utilisateur au niveau du composant qui a appelé la mutation ?

Bon, j'ai une approche assez déraisonnable, mais ça marche :

Je mets un booléen hasGraphError dans le cache et mets également en cache le message d'erreur.

const errorLink = onError(({ graphQLErrors, networkError }) => {
  if (graphQLErrors) {
    graphQLErrors.forEach(error => {
      // log gql error(s)
      console.log("[GraphQL error]: ", error);
      // cache error
      client.writeData({
        data: {
          hasGraphError: true,
          currentGraphError: error.message
        }
      });
    });
  }
  if (networkError) {
    // log network errors
    console.log("[Network error]: ", networkError);
  }
});

Ensuite, dans un composant MutationError, j'interroge le cache pour la présence d'erreur et le message d'erreur, rend conditionnellement l'erreur gql ou une vraie erreur réseau :

const HAS_ERROR = gql`
  query IsGraphErrorPresent {
    hasGraphError <strong i="11">@client</strong>
    currentGraphError <strong i="12">@client</strong>
  }
`;
export default function MutationError({ error }) {
  const { data } = useQuery(HAS_ERROR);
  const defaultErrorMessage =
    "We're having trouble connecting. Please check your internet connection and try again.";

  // real network error
  if (error && error.message.includes("Failed to fetch")) {
    return <Error>{defaultErrorMessage}</Error>;
  }

  // graph error
  if (error && data && data.hasGraphError) {
    return <Error>{data.currentGraphError}</Error>;
  }

  // probably a real server/network error
  if (error) {
    return <Error>{defaultErrorMessage}</Error>;
  }

  return null;
}

Ce sera global puisque j'en ai besoin sur toutes les mutations puisque mon serveur renvoie _toujours_ 400 pour ce qui devrait être 200 + erreurs graphql (je suis un peu salé à ce sujet)...

Donc, la chose importante ici, c'est que sur chaque mutation de composant, j'utilise un rappel onError vide qui empêche une exception non gérée d'Apollo, et en cas de succès, je dois me rappeler de réinitialiser le booléen hasGraphError dans le cache :

  const [someMutation, { loading, error, client }] = useMutation(SOME_MUTATION, {
    onError() {
      // this callback prevents apollo from throwing
      // ...unhandled exception on 400 status code
    },
    onCompleted({ someMutation }) {
      client.writeData({
        data: {
          hasGraphError: false
        }
      });
    }
  });

Ensuite, le composant d'erreur de mutation prend l'erreur useMutation comme accessoire (ce qui permet à la fois de déterminer les erreurs de réseau réelles et de s'assurer que nous ne rendons pas l'erreur gql globale en cache sur le mauvais composant) :

  {loading && <Spinner />}
  {error && <MutationError error={error} />}

Comme je l'ai dit, cette approche est assez déraisonnable, mais elle fonctionne actuellement pour résoudre :

  1. être généralement capable de gérer les erreurs graphql dans l'interface utilisateur même si la réponse a un code d'état non-200
  2. être spécifiquement capable de transmettre les erreurs de la configuration apollo-link-error au composant appelant, pour le rendu dans l'interface utilisateur

Problèmes avec cette approche telle que codée : cela écrit simplement la dernière erreur GQL du tableau dans le cache, de sorte qu'il ne prend pas en charge plusieurs erreurs GQL en même temps. Cela devrait être assez facile à gérer cependant, en construisant un tableau d'erreurs et en le stockant dans le cache, mais vous devrez définir un schéma/résolveurs locaux pour le faire, ou potentiellement juste JSON.stringify pour le stocker dans le cache sous forme de chaîne. Vous devrez également effacer le currentGraphError dans le cache en cas de succès, plutôt que de simplement définir le booléen sur false.

J'espère que ça aide quelqu'un !

De plus, au cas où cela aiderait, notez que errorPolicy ne fonctionne actuellement pas sur les hooks useMutation, c'est un bogue, et a été récemment abordé dans ce PR : https://github.com/apollographql/apollo-client/pull/5863 , mais n'a pas encore réussi à sortir.

Des progrès à ce sujet de la part des développeurs?

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

bwhitty picture bwhitty  ·  3Commentaires

j3ddesign picture j3ddesign  ·  3Commentaires

Nickersoft picture Nickersoft  ·  3Commentaires

NicholasLYang picture NicholasLYang  ·  4Commentaires

zsolt-dev picture zsolt-dev  ·  4Commentaires