<p>apollo-link-error gibt Fehler an Anrufer zurück</p>

Erstellt am 15. Apr. 2019  ·  17Kommentare  ·  Quelle: apollographql/apollo-link

Also verwende ich Apollo-link-error, um globale Authentifizierungs- und Admin-Fehler zu verwalten. Aber wenn ich es verwende, geben meine Fangmethoden in meinen Versprechen die Fehler nicht zurück.

Es sieht so aus, als ob alle Fehler apollo-link-error durchlaufen und nicht an die aufrufende Methode zurückgegeben werden.

Gibt es eine Möglichkeit, den Fehler an den Aufrufer zurückzugeben, damit ich einige Fehler lokal und einige Fehler global verwalten kann?

Hilfreichster Kommentar

Ich habe die Lösung gefunden, irgendwie seltsam, aber sie ist:

Dies druckt nur die Nachricht

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

ABER dies druckt den vollständigen Inhalt der Fehler

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

Ich denke, dieses Thema kann geschlossen werden
@Nosherwan @romucci @Sceat @lbrdar

Alle 17 Kommentare

Ich habe das gleiche Problem in meiner App. Ich möchte alle Fehler im Fehlerlink abfangen (zum Beispiel, damit ich sie protokollieren kann), aber ich möchte sie auch an den ursprünglichen Anrufer weiterleiten und dort behandeln, da sie möglicherweise eine benutzerdefinierte Fehlernachricht enthalten, die dem Benutzer angezeigt werden muss .

Mein Code:

  • beim Anbieter:
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(),
});

  • im Bauteil:
 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) {
        ....
      }
    });

Beachten Sie, dass das Aufrufen von forward nicht hilft, da es undefined als Argument an then zurückgibt, sodass ich weder Daten noch Fehler habe und errors auf null ist auch keine Option, da ich tatsächlich Fehler lesen muss.

@lbrdar Haben Sie dafür eine

Nein

@lbrdar Geht das nicht mit einem Haken?

 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 Ich stehe vor dem gleichen Problem. Haben Sie das am Ende gelöst?

@Nosherwan Ich habe gerade Version 1.1.11 installiert und alles funktioniert jetzt gut ... Sie können auch Ihre inneren Versprechen überprüfen (vielleicht haben Sie irgendwo vergessen, ein Versprechen in einem anderen Versprechen zurückzugeben)

@merksam danke für den Kommentar.
Ich verwende genau die gleiche Version wie du. Das Verhalten ist leider das gleiche.

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

Im obigen Codeblock werden die graphQLErrors abgefangen und im onError-Handler kann etwas getan werden. Diese Fehler werden jedoch nicht an das eigentliche Aufrufversprechen weitergegeben.
Ich verwende asynchrone Funktionen, also verwende ich anstelle von "then" das Schlüsselwort await, und das befindet sich in einem try-catch-Block.
der catch-Block fängt den Fehler ab, aber es wird kein Fehler an ihn übergeben.

Hat jemand dafür einen Workaround gefunden?

@Nosherwan @prem-prakash Könnten wir uns irgendwo im Chat kontaktieren oder sogar anrufen, damit wir versuchen herauszufinden, warum es in meinem Fall funktioniert und in Ihrem nicht? (falls es noch relevant ist)

Ich habe die Lösung gefunden, irgendwie seltsam, aber sie ist:

Dies druckt nur die Nachricht

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

ABER dies druckt den vollständigen Inhalt der Fehler

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

Ich denke, dieses Thema kann geschlossen werden
@Nosherwan @romucci @Sceat @lbrdar

Wie wäre es, dies in die Dokumentation aufzunehmen?

Tut mir leid, aber die obige Lösung funktioniert nicht. Ich schätze, ein vollständiges Beispiel dafür, wie die graphqlErrors in Link-Error an den ursprünglichen Aufrufer zurückgesendet werden.

In meinem Fall erhält das folgende ApolloQueryResult-Objekt bei einem Fehler nicht die Fehlerdetails, die in onError getröstet werden. Einige im Versuch ... fangen den Anruf ein. Die graphqlError-Details können nicht vom Server abgerufen werden. Nur ein "400er Fehler"..

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

Serverkonfiguration:

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 danke.... Retter..

Dieses Problem ist äußerst hartnäckig. Ich habe keine Kontrolle über den graphql-Server in meinem Projekt, nur den Client. Der Server antwortet mit graphql-Fehlern in der richtigen Form, jedoch mit einem 400-Statuscode. Im Fehlerlink habe ich Zugriff auf graphQLErrors , aber in der Komponentenmutation, wenn ich graphQLErrors herausziehe, wie von @prem-prakash vorgeschlagen, ist graphQLErrors ein leeres Array . Ich kann nur auf eine Standardmeldung "Fehler: Netzwerkfehler: Antwort nicht erfolgreich: Statuscode 400 erhalten" zugreifen. Apollo vernichtet die menschenlesbaren Fehlermeldungen des Servers ("Benutzer oder Passwort falsch"), weil der 400-Statuscode ein Punkt für Apollo ist.

Gibt es jemanden, der erfolgreich eine 400-Statuscode-Antwort mit Fehlermeldungen verarbeiten und diese Meldung an die Benutzeroberfläche der Komponente weitergeben kann, die die Mutation aufgerufen hat?

Okay, ich habe einen ziemlich unvernünftigen Ansatz, aber er funktioniert:

Ich setze einen booleschen hasGraphError in den Cache und speichere auch die Fehlermeldung.

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);
  }
});

Dann frage ich in einer MutationError-Komponente den Cache auf das Vorhandensein eines Fehlers und der Fehlermeldung ab, rendere bedingt den gql-Fehler oder einen echten Netzwerkfehler:

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;
}

Dies wird global sein, da ich es für alle Mutationen benötige, da mein Server _immer_ 400 zurückgibt für was 200 + graphql-Fehler sein sollten (ich bin da etwas salzig) ...

Das Wichtigste hier ist also, dass ich bei jeder Komponentenmutation einen leeren onError-Callback verwende, der eine unbehandelte Ausnahme von Apollo verhindert, und bei Erfolg muss ich daran denken, den booleschen hasGraphError-Wert im Cache zurückzusetzen:

  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
        }
      });
    }
  });

Dann nimmt die Mutationsfehlerkomponente den useMutation-Fehler als Requisiten (was beides ermöglicht, echte Netzwerkfehler zu bestimmen und sicherzustellen, dass wir den globalen zwischengespeicherten gql-Fehler nicht auf der falschen Komponente rendern):

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

Wie gesagt, dieser Ansatz ist ziemlich unvernünftig, aber er arbeitet derzeit an der Lösung:

  1. im Allgemeinen in der Lage sein, graphql-Fehler in der Benutzeroberfläche zu behandeln, selbst wenn die Antwort einen Statuscode von nicht 200 hat
  2. insbesondere in der Lage sein, Fehler aus der apollo-link-error-Konfiguration an die aufrufende Komponente zum Rendern in der Benutzeroberfläche zu übergeben

Probleme mit diesem codierten Ansatz: Dies schreibt nur den letzten GQL-Fehler im Array in den Cache, sodass nicht mehrere GQL-Fehler gleichzeitig unterstützt werden. Dies sollte jedoch ziemlich einfach zu verwalten sein, indem Sie ein Array von Fehlern erstellen und diese im Cache speichern, aber Sie müssen dafür ein lokales Schema/Resolver definieren oder möglicherweise einfach JSON.stringify, um es im Speicher zu speichern Cache als String. Sie müssen bei Erfolg auch den currentGraphError im Cache löschen, anstatt den booleschen Wert einfach auf false zu setzen.

Hoffe es hilft jemandem!

Falls es hilft, beachten Sie auch, dass errorPolicy derzeit nicht bei useMutation-Hooks funktioniert, dies ist ein Fehler und wurde kürzlich in dieser PR behoben: https://github.com/apollographql/apollo-client/pull/5863 , aber hat es noch nicht zur Veröffentlichung geschafft.

Gibt es diesbezüglich Fortschritte seitens der Entwickler?

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen