Apollo-link-rest: Estratégia recomendada para lidar com erros 404?

Criado em 6 jun. 2018  ·  12Comentários  ·  Fonte: apollographql/apollo-link-rest


É bastante comum para uma API REST usar uma resposta 404 para indicar que um registro não existe. Agora, quando isso acontece, o resultado é um networkError que parece, por padrão, ser tratado como um erro mais fatal do que um erro GraphQL pela pilha do Apollo.

Por exemplo, com a consulta:

query BookQuery($slug: ID!) {
  book(slug: $slug) @rest(type: "Book", path: "book/:slug") {
    name
    author
  }
}

Se o ponto de extremidade retornar 404, ele rejeitará com um erro de rede que deve ser tratado onde a intenção provavelmente apenas usará a propriedade de renderização error para exibir a mensagem de erro não fatal para um usuário. ou seja, se fosse uma consulta GraphQL em vez de REST, isso não seria classificado como um erro de rede e seria tratado dessa forma.

O que fiz para corrigir isso foi adicionar um cheque ao meu error-link que transforma o erro de rede 404 em um erro GraphQL:

forward(operation).subscribe({
  next: result => {...},
  error: networkError => {
    if (networkError.statusCode === 404) {
      return observer.next({errors: [networkError]});
    }
    //...
    observer.error(networkError);
  },
  complete: observer.complete.bind(observer),
});

Provavelmente ainda há espaço para melhorias, mas ele resolve o problema.

Eu estava me perguntando se isso poderia / deveria ser resolvido de alguma forma em apollo-link-rest , então decidi iniciar a conversa.

enhancement💡 question❔

Todos 12 comentários

Essa é uma ótima pergunta. - Eu adoraria que esse padrão fosse adicionado como uma sugestão à documentação. Eu acho que é uma classe de problemas que vários Apollo-links sofrem (apollo-link-state vem à mente).

Não sei se temos certeza de que essa é a resposta certa para todos os usuários do ApolloLink, no entanto?

É assim que todos os erros de http são tratados no apollo-link-rest

        if (res.status >= 300) {
          // Throw a JSError, that will be available under the
          // "Network error" category in apollo-link-error
          let parsed: any;
          try {
            parsed = await res.json();
          } catch (error) {
            // its not json
            parsed = await res.text();
          }
          rethrowServerSideError(
            res,
            parsed,
            `Response not successful: Received status code ${res.status}`,
          );
        }
        return res;

talvez nós adicionemos uma função de correspondência de caso que permite aos usuários ditar como o erro é processado.
Pode fornecer alguns utilitários padrão úteis para casos comuns como 404 == null

Embora eu compartilhe da preocupação de @fbartho de que uma solução que apresentamos pode não ser a certa para todos os usuários deste link, pensei em um caso em que um erro 404 é particularmente prejudicial. Se pegarmos este exemplo dos testes:

query postAndTags {
  post @rest(type: "Post", path: "/post/1") {
    id
    title
  }
  tags @rest(type: "[Tag]", path: "/tags") {
    name
  }
}

e post não existe e retorna um 404, então toda a consulta falha em um erro de rede. Embora isso possa ser desejado em alguns casos, parece que o resultado deveria ser:

const data = {
  post: null,
  tags: [{ name: 'apollo' }, { name: 'graphql' }],
}

Se quisermos atender a isso, adicionar tratamento de erro adicional, como sugere @paulpdaniels , será muito fácil. Olhando para os erros 4xx, só consigo ver realmente 404 e 400/412/422 (em mutações), possivelmente sendo erros não fatais que requerem tratamento especial, seja como erros GraphQL ou definindo o resultado como null .

A questão permanece se é razoável fornecer algum manipulador fixo para esses erros ou se ele deve ser deixado para o error-link ou aplicativo. Uma vez que múltiplas consultas de mutação não são suportadas (eu acho?), A única falha atual que parece particularmente relevante é o exemplo 404 que comecei acima.

Também existe a opção de adicionar um manipulador de erros à configuração, mas parece que pode estar roubando a funcionalidade de um error-link que realmente pertence a ele. Também pode tornar a API deste link desnecessariamente complexa.

@marnusw Essa é uma ótima resposta. Eu apoiaria uma correção que implementasse seu comportamento por padrão!

142 adiciona tratamento de erros 404. Acho que é o mais importante desta discussão.

Com base em muitos padrões de API restantes , todos os códigos de erro devem sempre incluir uma mensagem legível por humanos. Anular esse resultado, como foi feito no nº 142, está em oposição direta a isso.

Eu coloquei um PR para restabelecer 404 como erros normais de rede, para coincidir com as boas práticas de API REST: https://github.com/apollographql/apollo-link-rest/pull/283

@christrude embora eu não possa discordar de você no que diz respeito às APIs REST, o objetivo desta biblioteca é fazer com que as APIs REST funcionem como GraphQL. Portanto, se a abordagem GraphQL para recursos ausentes é retornar null , então esta biblioteca deve converter a convenção RESTful 404 para a convenção de valor de retorno GraphQL null .

@christrude embora eu não possa discordar de você no que diz respeito às APIs REST, o objetivo desta biblioteca é fazer com que as APIs REST funcionem como GraphQL. Portanto, se a abordagem GraphQL para recursos ausentes é retornar null , então esta biblioteca deve converter a convenção RESTful 404 para a convenção de valor de retorno GraphQL null .

Então, como o GraphQL propõe que você lide com uma resposta 404 na IU? Fazer nada? Então, os pedidos morrem silenciosamente? Isso é um gerenciamento de UX / api incrivelmente ruim / ruim.

Se você consultar um item por ID e obtiver um valor nulo de volta, trate disso de acordo na IU. Se contiver dados, exiba-os.

Eu concordo com @marnusw aqui, não podemos controlar o que a API restante do usuário faz, então a biblioteca não deve ser excessivamente restritiva no que ela permite. O mapeamento 404 => nulo é uma semântica relativamente intuitiva que permite mover do modelo de recurso único por solicitação de REST para o modelo de vários recursos por solicitação (da perspectiva do cliente) de GraphQL, sem explodir em dados ausentes.

Talvez pudesse haver uma maneira melhor de cancelar esse comportamento, como uma versão pré-empacotada do transformador de resposta ou uma abstração da lógica de tratamento de solicitação que permite ao usuário controlar totalmente o tratamento de status http. Mas não acho que reverter o comportamento anterior seja a abordagem certa.

Parte do problema da abordagem é que na assinatura de resultado você não tem conhecimento se é um resultado nulo porque é um 404, ou se é um retorno sem conteúdo 201 ou algo semelhante. Eu corrigi isso no afterware, verificando o status e forçando-o a lançar um erro que assume o problema porque não consigo acessar a mensagem de erro do servidor real, especialmente no meu caso porque usamos a busca personalizada para injetar um token de autenticação , e não pode usá-lo para obter a resposta antes de apollo excluí-lo. Minha solução é um cobertor ruim para outra resposta 404 em todo o aplicativo, além de um caso.

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