<p>apollo-link-error devuelve el error a la persona que llama</p>

Creado en 15 abr. 2019  ·  17Comentarios  ·  Fuente: apollographql/apollo-link

Entonces estoy usando Apollo-link-error para administrar los errores globales de autenticación y administración. Pero si lo uso, mis métodos de captura en mis promesas no devuelven los errores.

Parece que todos los errores pasan por apollo-link-error y no se devuelven al método de la persona que llama.

¿Hay alguna forma de devolver el error a la persona que llama para poder administrar algunos errores localmente y algunos errores a nivel mundial?

Comentario más útil

Encontré la solución, un poco extraña, pero es:

Esto imprime solo el mensaje

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

PERO esto imprime el contenido completo de los errores

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

Creo que este problema se puede cerrar.
@Nosherwan @romucci @Sceat @lbrdar

Todos 17 comentarios

Tengo el mismo problema en mi aplicación. Quiero detectar todos los errores en el enlace de error (por ejemplo, para poder registrarlos) pero también quiero reenviarlos a la persona que llama original y manejarlos allí, ya que pueden contener un mensaje de error personalizado que debe mostrarse al usuario .

Mi código:

  • en proveedor:
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 componente:
 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) {
        ....
      }
    });

Tenga en cuenta que llamar a forward no ayudará, ya que devuelve indefinido como un argumento a then por lo que no tendría datos ni errores y establecería errors en null tampoco es una opción, ya que en realidad necesito leer errores.

@lbrdar ¿Ha encontrado alguna solución para esto?

Nop 😞

@lbrdar ¿No es la forma de hacer esto con una trampa?

 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 Estoy enfrentando el mismo problema. ¿Ustedes terminaron resolviendo esto?

@Nosherwan Acabo de instalar la versión 1.1.11 y todo funciona bien ahora ... También puede verificar sus promesas internas (tal vez en algún lugar olvidó devolver una promesa dentro de otra promesa)

@merksam gracias por el comentario.
Estoy usando exactamente la misma versión que tú. Desafortunadamente, el comportamiento es el mismo.

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

En el bloque de código anterior, se detectan los errores graphQLErrors y se puede hacer algo en el controlador onError. Sin embargo, esos errores no se pasan a la promesa de llamada real.
Estoy usando funciones asíncronas, así que en lugar de 'entonces' estoy usando la palabra clave await, y eso está dentro de un bloque try catch.
el bloque de captura detecta el error, pero no se le pasa ningún error.

¿Alguien ha encontrado alguna solución para esto?

@Nosherwan @ prem-prakash ¿Podríamos comunicarnos en algún lugar del chat o incluso hacer una llamada para tratar de averiguar por qué funciona en mi caso y no en el tuyo? (si sigue siendo relevante)

Encontré la solución, un poco extraña, pero es:

Esto imprime solo el mensaje

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

PERO esto imprime el contenido completo de los errores

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

Creo que este problema se puede cerrar.
@Nosherwan @romucci @Sceat @lbrdar

¿qué hay de agregar esto a la documentación?

Lo siento, pero la solución anterior no funciona. Supongo que hay un ejemplo completo sobre cómo devolver el error graphqlErrors en link-error al llamador inicial.

En mi caso, cuando hay un error, el siguiente objeto ApolloQueryResult no obtiene los detalles del error en el onError. Algunos en el intento ... captura en torno a la llamada. No se pueden obtener los detalles de graphqlError del servidor. Solo un "error 400" ...

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

configuración del servidor:

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 gracias .... salvador ..

Este problema es extremadamente persistente. No tengo control sobre el servidor graphql en mi proyecto, solo el cliente. El servidor responde con errores de graphql en la forma correcta, pero con un código de estado 400. En el enlace de error tengo acceso a graphQLErrors , pero en la mutación del componente, cuando saco graphQLErrors como lo sugiere @ prem-prakash, graphQLErrors es una matriz vacía . Solo puedo acceder a un mensaje predeterminado "Error: error de red: respuesta no satisfactoria: código de estado recibido 400". Apollo está superando los mensajes de error legibles por humanos del servidor ("usuario o contraseña incorrectos") porque el código de estado 400 es un punto final para Apollo.

¿Hay alguien que pueda manejar con éxito una respuesta de código de estado 400 con mensajes de error y pasar ese mensaje a la interfaz de usuario en el componente que llamó a la mutación?

Bueno, tengo un enfoque bastante irracional, pero está funcionando:

Estoy configurando un hasGraphError booleano en el caché y también estoy almacenando en caché el mensaje de error.

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

Luego, en un componente MutationError, consulto la caché en busca de error y el mensaje de error, renderizo condicionalmente el error gql o un error de red real:

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

Esto será global, ya que lo necesito en todas las mutaciones, ya que mi servidor _siempre_ devuelve 400 por lo que deberían ser 200 + errores de graphql (estoy un poco salado sobre eso) ...

Entonces, lo importante aquí es que en cada mutación de componente, uso una devolución de llamada onError vacía que evita una excepción no controlada de Apollo, y en caso de éxito debo recordar restablecer el valor booleano hasGraphError en el caché:

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

Luego, el componente de error de mutación toma el error useMutation como accesorios (lo que permite que se determinen errores de red reales y se asegura de que no estemos representando el error gql global en caché en el componente incorrecto):

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

Como dije, este enfoque es bastante irrazonable, sin embargo, actualmente está trabajando para resolverlo:

  1. generalmente puede manejar errores de graphql en la interfaz de usuario incluso si la respuesta tiene un código de estado que no sea 200
  2. específicamente, poder pasar errores de la configuración apollo-link-error al componente de llamada, para renderizar en la interfaz de usuario

Problemas con este enfoque codificado: esto solo escribe el último error de GQL en la matriz en la caché, por lo que no admite varios errores de GQL al mismo tiempo. Sin embargo, esto debería ser bastante fácil de administrar, construyendo una matriz de errores y almacenándola en el caché, pero tendrá que definir un esquema / resolutores locales para hacer esto, o potencialmente solo JSON. caché como una cadena. También necesitará borrar el currentGraphError en el caché en caso de éxito, en lugar de simplemente establecer el booleano en falso.

¡Espero que ayude a alguien!

Además, en caso de que sea útil, tenga en cuenta que errorPolicy actualmente no funciona en los ganchos de useMutation, esto es un error, y se abordó recientemente en este PR: https://github.com/apollographql/apollo-client/pull/5863 , pero no ha salido a la venta en este momento.

¿Algún progreso en esto por parte de los desarrolladores?

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

j3ddesign picture j3ddesign  ·  3Comentarios

SaschaDens picture SaschaDens  ·  3Comentarios

ChenRoth picture ChenRoth  ·  4Comentarios

ignivalancy picture ignivalancy  ·  5Comentarios

lobosan picture lobosan  ·  3Comentarios