<p>apollo-link-error erro de retorno ao chamador</p>

Criado em 15 abr. 2019  ·  17Comentários  ·  Fonte: apollographql/apollo-link

Portanto, estou usando o Apollo-link-error para gerenciar erros globais de autenticação e administração. Mas se eu usá-lo, meus métodos catch em minhas promessas não retornam os erros.

Parece que todos os erros passam por apollo-link-error e não são passados ​​de volta ao método do chamador.

Existe uma maneira de retornar o erro ao chamador para que eu possa gerenciar alguns erros localmente e alguns erros globalmente?

Comentários muito úteis

Achei a solução meio esquisita, mas é:

Isso imprime apenas a mensagem

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

MAS isso imprime todo o conteúdo dos erros

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

Eu acho que esse problema pode ser resolvido
@Nosherwan @romucci @Sceat @lbrdar

Todos 17 comentários

Eu tenho o mesmo problema em meu aplicativo. Eu quero pegar todos os erros no link de erro (por exemplo, para que eu possa registrá-los), mas também quero encaminhá-los para o chamador original e tratá-los lá, pois podem conter uma mensagem de erro personalizada que precisa ser exibida ao usuário .

Meu código:

  • no provedor:
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(),
});

  • no 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) {
        ....
      }
    });

Observe que chamar forward não ajudará, pois retorna indefinido como um argumento para then então eu não teria nem dados nem erro e configuração errors para null também não é uma opção, pois eu realmente preciso ler os erros.

@lbrdar Você encontrou alguma solução alternativa para isso?

Não 😞

@lbrdar A maneira de fazer isso não é

 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 Estou enfrentando o mesmo problema. Vocês acabaram resolvendo isso?

@Nosherwan Acabei de instalar a versão 1.1.11 e tudo funciona bem agora ... Você também pode verificar suas promessas internas (talvez em algum lugar você tenha esquecido de retornar uma promessa dentro de outra promessa)

@merksam obrigado pelo comentário.
Estou usando exatamente a mesma versão que você. Infelizmente, o comportamento é o mesmo.

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

No bloco de código acima, os graphQLErrors são capturados e algo pode ser feito no manipulador onError. No entanto, esses erros não são passados ​​para a promessa de chamada real.
Estou usando funções assíncronas, portanto, em vez de 'then', estou usando a palavra-chave await e isso está dentro de um bloco try catch.
o bloco catch detecta o erro, mas nenhum erro é transmitido a ele.

Alguém encontrou alguma solução alternativa para isso?

@Nosherwan @ prem-prakash Podemos entrar em contato em algum lugar no chat ou até mesmo fazer uma ligação para tentar descobrir por que está funcionando no meu caso e não no seu? (se ainda for relevante)

Achei a solução meio esquisita, mas é:

Isso imprime apenas a mensagem

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

MAS isso imprime todo o conteúdo dos erros

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

Eu acho que esse problema pode ser resolvido
@Nosherwan @romucci @Sceat @lbrdar

que tal adicionar isso à documentação?

Desculpe, mas a solução acima não funciona. Eu acho que um exemplo completo de como enviar de volta o graphqlErrors no link-error para o chamador inicial.

No meu caso, quando há um erro, o seguinte objeto ApolloQueryResult não obtém os detalhes do erro consolados no onError. Alguns tentam ... pegar em torno da chamada. Não é possível obter os detalhes do graphqlError do servidor. Apenas um "erro 400" ..

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

configuração do 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 obrigado .... salvador ..

Este problema é extremamente persistente. Não tenho controle sobre o servidor Graphql em meu projeto, apenas sobre o cliente. O servidor está respondendo com erros graphql no formato correto, mas com um código de status 400. No link de erro, tenho acesso a graphQLErrors , mas na mutação do componente, quando retiro graphQLErrors como sugerido por @ prem-prakash, graphQLErrors é uma matriz vazia . Só consigo acessar a mensagem padrão "Erro: Erro de rede: Resposta malsucedida: Código de status recebido 400". O Apollo está eliminando as mensagens de erro legíveis por humanos do servidor ("usuário ou senha incorreta") porque o código de status 400 é um ponto final para o Apollo.

Existe alguém por aí que pode lidar com sucesso com uma resposta de código de status 400 com mensagens de erro e passar essa mensagem para a IU no componente que chamou a mutação?

Ok, bem, eu tenho uma abordagem bastante irracional, mas está funcionando:

Estou definindo um booleano hasGraphError no cache e também armazenando em cache a mensagem de erro.

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

Em seguida, em um componente MutationError, eu consulto o cache para a presença de erro e a mensagem de erro, condicionalmente renderizo o erro gql ou um erro real de rede:

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

Isso será global, pois eu preciso disso em todas as mutações, já que meu servidor _sempre_ retorna 400 para o que deveria ser 200 + erros de graphql (estou um pouco salgado sobre isso) ...

Portanto, o importante aqui é que em cada mutação de componente, eu uso um retorno de chamada onError vazio que evita uma exceção não tratada do Apollo e, em caso de sucesso, devo lembrar de redefinir o booleano hasGraphError no 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
        }
      });
    }
  });

Em seguida, o componente de erro de mutação usa o erro useMutation como props (o que permite que erros reais de rede sejam determinados e garante que não estejamos processando o erro global em cache gql no componente errado):

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

Como eu disse, essa abordagem não é razoável, mas atualmente está trabalhando para resolver:

  1. geralmente é capaz de lidar com erros do Graphql na IU, mesmo se a resposta tiver um código de status diferente de 200
  2. especificamente ser capaz de passar erros da configuração de erro de link-apollo para o componente de chamada, para renderização na IU

Problemas com esta abordagem como codificada: isso apenas grava o último erro GQL na matriz no cache, portanto, não é compatível com vários erros GQL ao mesmo tempo. No entanto, isso deve ser bastante fácil de gerenciar, criando uma série de erros e armazenando-os no cache, mas você terá que definir um esquema / resolvedores locais para fazer isso, ou potencialmente apenas JSON.stringify para armazenar no cache como uma string. Você também precisará limpar o currentGraphError no cache em caso de sucesso, em vez de apenas definir o booleano como falso.

Espero que ajude alguém!

Além disso, caso ajude, observe que errorPolicy atualmente não funciona em ganchos useMutation, este é um bug e foi abordado recentemente neste PR: https://github.com/apollographql/apollo-client/pull/5863 , mas não conseguiu lançar neste momento.

Algum progresso por parte dos desenvolvedores?

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

ignivalancy picture ignivalancy  ·  5Comentários

j3ddesign picture j3ddesign  ·  3Comentários

NicholasLYang picture NicholasLYang  ·  4Comentários

valerybugakov picture valerybugakov  ·  5Comentários

Kisepro picture Kisepro  ·  4Comentários