Apollo-link-rest: Tratamento de resposta de erro

Criado em 2 out. 2018  ·  16Comentários  ·  Fonte: apollographql/apollo-link-rest

Olá, tenho esta API de login que terá o corpo da solicitação como:

{
    "authentications": {
        "emailAddress": "[email protected]",
        "password": "11111111"
    }
}

O token de retorno do servidor se for bem-sucedido:

{
    "authentications": {
        "token": "eyJhbGoiU3RvcmUifV0sImNyZWF0ZWRBdCI6IjIwMTgtMDktMTZUMTg6NTA6NTYuNT"
    }
}

Caso a entrada de e-mail ou senha esteja incorreta, ele retornará:

{
    "message": "Cannot find document for class 'User'. searched with parameters: '{\"emailAddress\":\"[email protected]\"}'",
    "errorCode": 1103,
    "status": 404
}

Posso fazer login com sucesso com um esquema GraphQL como este:

gql`
  fragment Authentications on any {
    emailAddress: String
    password: String
  }

  fragment AuthInput on REST {
    authentications {
      Authentications
    }
  }

  mutation signIn($input: AuthInput!) {
    authPayload(input: $input) 
      @rest(type: "AuthPayload", path: "/api/v1/authentications", endpoint:"UsersService", method:"POST") {
      authentications @type(name:"Auth"){
        token
      }
    }
  }
`;

Minha dúvida é como posso obter a resposta em caso de erro (e-mail / senha incorretos)? Porque agora, se o servidor retornar um erro, a resposta será sempre nula:

Object {
    "data": Object {
        "authPayload": null,
    },
    "errors": undefined,
}
help wanted 🛠 question❔

Comentários muito úteis

Eu também estou preso neste assunto. Existe um motivo para não retornar a resposta 404 completa em vez de nula?

Todos 16 comentários

Se você não conseguir detectar o erro 400+, acho que esse problema será útil.
https://github.com/apollographql/apollo-link-rest/issues/151

Para sua informação: para credenciais incorretas, você deve retornar 401.
https://stackoverflow.com/questions/1959947/whats-an-adequ-http-status-code-to-return-by-a-rest-api-service-for-a-val

Olá a todos,

Acabei de me deparar com isso e também estou me perguntando qual é a maneira recomendada de lidar com um 404. Ele não aciona apollo-link-error por exemplo.

Até agora, estou pensando em escrever um link de manipulador de erros personalizado ou verificar o conteúdo de dados na resposta em cada componente <Query /> .

FWIW Tenho o mesmo caso em que um servidor está retornando um 404 em vez de um 401, por exemplo, mas alterar o servidor infelizmente não é uma opção neste momento.

Acho que valeria a pena abordar esse caso de uso porque os códigos de status para REST são muito diferentes - e mais variados e importantes - do que os do GraphQL.

Eu também estou preso neste assunto. Existe um motivo para não retornar a resposta 404 completa em vez de nula?

Ainda estou para encontrar um caso em que não tratar o 404 como um erro tenha me ajudado, continuo tentando encontrar uma boa maneira de contornar esse fato.

É o pensamento de que 404 Not found poderia descrever uma consulta de dados que com sucesso, produz corretamente o conjunto vazio?

Também pode sinalizar que os proprietários do serviço fizeram uma alteração significativa que um ponto de extremidade disponível anteriormente desapareceu.

Acho que o primeiro caso poderia ser melhor tratado por 200 OK junto com uma entidade de aplicativo vazia ou nula. Pelo menos, parece que esses dois casos devem ser facilmente discerníveis pelo cliente, pois são muito diferentes.

Sim, conjuntos de dados intencionalmente vazios são um pouco mais comuns do que se possa imaginar? (Pelo menos fiquei surpreso!) Como os usuários costumam coletar várias redes e outras chamadas em uma única meta chamada, o padrão de lançar um erro no 404 tem um impacto desproporcional, porque um 404 encerraria todas as outras buscas de dados que acontecem em paralelo. Concordo que se houvesse apenas uma chamada REST por consulta GraphQL executada, parecia-me que deveríamos lançar um erro devido à semântica oficial REST.

Na prática, não lançar um erro por padrão parecia melhor! Já que você pode contornar isso adicionando uma busca personalizada, e isso parece “seja liberal no que você aceita”; essa escolha parece corresponder a um dos principais objetivos do Apollo-link-rest: ajudar os usuários que não necessariamente controlam o back-end, e há muitos servidores apenas “principalmente REST” por aí, então violações semânticas são comuns .

@williamboman é relativamente simples configurar Apollo-link-rest para lançar 404s se você usar o parâmetro customFetch Não estou no meu computador, mas me avise se precisar de ajuda para fazer isso!

Olá @fbartho, por favor, me ajude a escrever customFetch para lidar com erros 404? Existe algum exemplo sobre isso?

@anasnain :

Em javascript, seria algo assim:

export async function customFetch(requestInfo, init) {
  const response = await fetch(requestInfo, init);
  if (response.status === 404) {
    throw new Error("404 File Not Found"); // Customize this however you like!
  }
  return response;
}

(No TypeScript seria um pouco mais detalhado)

@fbartho Obrigado pela resposta rápida. Consigo pegar 404 agora.
Mas como posso ter certeza de que o networkError de apollo-link-error captura o erro (lance um novo erro ("404 Arquivo não encontrado")) escrito na busca personalizada?

Ah, infelizmente, acho que ele aparecerá anexado ao array graphQLErrors (não na propriedade networkError ) devido às regras internas do ApolloClient (sobre como os links funcionam).

É possível que isso possa ser corrigido, mas não sei como. - O HTTPLink deve saber como fazê-lo e não tive oportunidade de investigar. Temos um método auxiliar em nossa base de código (de trabalho) que apenas descompacta os erros aninhados. (Isso também era necessário para erros lançados de apollo-link-state para nós, então não era realmente uma prioridade)

@fbartho Não estou recebendo nenhum erro neste caso. os dados estão retornando nulos. estava esperando um erro em vez de dados, se estivermos lançando um erro. Não tenho certeza de como implementar isso.

@anasnain Faz tanto tempo desde que eu configurei que esqueci.

Você também precisa configurar uma instância apollo-link-error, esta é minha configuração:

const attachGQLErrorsToNetworkError = (
    graphQLErrors: readonly GraphQLError[],
    networkError: Error,
): void => {
    (networkError as any).tr_graphQLErrors = graphQLErrors;
    return;
};

/** Set behavior when errors occur and handle our own TR errors */
export const apolloErrorLink = onError((errorResponse: ErrorResponse) => {
    const {
        graphQLErrors = [],
        networkError,
    }: {
        graphQLErrors?: readonly GraphQLError[];
        networkError?: Error;
    } = errorResponse;

    /**
     * Our error parsing (function recursiveGQLErrorsFromNetworkError) rely
     * on attaching the following graphql errors.
     * Let's make sure to not attach anything `wrong` (ie: null, empty, ...)
     */
    const hasGraphQLErrors: boolean =
        graphQLErrors != null &&
        Array.isArray(graphQLErrors) &&
        graphQLErrors.length > 0;

    if (networkError && hasGraphQLErrors) {
        /*
         * graphQLErrors are not being passed through the chain of links,
         * but network errors are attaching the graphQLErrors to networkError
         * to be able to access them in a component
         */
        attachGQLErrorsToNetworkError(graphQLErrors, networkError);
    }
});

Após mais reflexão: Não tenho certeza se entendi a situação que você está descrevendo.

O problema é que você não consegue ler o "erro 404" em seu código de componente / reação?

@fbartho
Cenário: Estou executando a APIquery abaixo do resto e a expectativa é obter um objeto de erro caso ele retorne o código de erro 404, assim como no caso de outros erros 4xx e 5xx. mas, neste caso, o erro é indefinido e os dados são nulos.
const {carregamento, erro, dados} = useQuery (CLIENT_API_QUERY);

Esta é a instância do cliente Apollo:

async function customFetch(requestInfo, init) {
    const response = await fetch(requestInfo, init);
    if (response.status === 404) {
        response.json().then((errorResponse) => {
          throw new Error(errorResponse);
        });
    }
    return response;
  }

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

const restLink = new RestLink({
    uri: 'https://run.mocky.io/v3/df72bacd-39cb-476d-bfda-06d7f5e9d77d',
    customFetch: (requestInfo, init) => customFetch(requestInfo, init)
});

const apolloClient = new ApolloClient({
    link: ApolloLink.from([errorLink, restLink]),
    new InMemoryCache(),
  });
export default apolloClient;

@anasnain - uma coisa que estou ciente é que não acho que você pode passar um objeto arbitrário ao fazer new Error

Além disso, acho que você está perdendo um await, então a instrução throw está acontecendo fora da chamada restLink customFetch!

const err = new Error("404 Error");
try {
  err.responseJson = await response.json(); // This await crucial to get the error in the right spot!
} catch (parsingError) {
  // figure out what you want to do with parsingError?
}
throw err;
Esta página foi útil?
0 / 5 - 0 avaliações