Apollo-link-rest: Como acessar response.headers com apollo-link-rest?

Criado em 11 nov. 2020  ·  6Comentários  ·  Fonte: apollographql/apollo-link-rest

Olá a todos,

Eu queria usar apollo-link-rest para acessar uma api rest, no entanto, não posso acessar por useQuery () o response.headers .

Por exemplo, uma api rest com paginação, que coloca as informações first, prev, next, last no cabeçalho. Como posso acessar isso?

Fiz um exemplo aqui: https://codesandbox.io/embed/how-to-access-response-0mqx7?file=/src/Client.ts

Você pode ir para a aba ferramentas de desenvolvimento Network , ver a resposta com Cabeçalhos , no link , está a informação de paginação. Mas não tenho ideia de como acessar o Headers ....

Este é o meu código principal, não tenho ideia de como obter o response.headers.link ...

  const queryTodos = gql`
      query Todos($page: number, $limit: number) {
        todos(_page: $page, _limit: $limit)
          @rest(type: "[Todo]", path: "/todos/?{args}") {
            userId
            id
            title
            completed
        }
     }
   `;

export const Todos = () => {
  const { data, loading, error } = useQuery(queryTodos, {
    variables: { page: 1, limit: 3 },
    fetchPolicy: "no-cache"
  });

 ...

  return (<div>...</div>)

Eu também fiz esta pergunta em stackoverflow: https://stackoverflow.com/q/64791676/3279996 , caso você goste de ter mais pontos em stackoverflow. : D

enhancement enhancement💡 feature help wanted 🛠 question❔

Todos 6 comentários

@blatoo - infelizmente, esse é um recurso que não existe atualmente no apollo-link-rest.

Fundamentalmente, GraphQL não espera lidar com cabeçalhos - porque eles teriam que ser retornados no fundo do gráfico.

Se alguém quisesse implementar isso, eu poderia nos ver adicionando __headers como um campo secreto / automático no "corpo" de uma resposta, mas teríamos que adicionar um sinalizador de recurso para habilitar esse comportamento, e faça algumas alterações nas chaves do cabeçalho para que sejam compatíveis com o Graphql.

const queryTodos = gql`
      query Todos($page: number, $limit: number) {
        todos(_page: $page, _limit: $limit)
          @rest(type: "[Todo]", path: "/todos/?{args}") {
+             __headers {
+                         XMyHeader
+             }
            userId
            id
            title
            completed
        }
     }
   `;

@fbartho muito obrigado por esta resposta. Seria um ótimo recurso, se pudéssemos acessar as informações do cabeçalho. Eu uso json-server, eles colocam as informações de paginação no Headers , também para as informações de paginação baseadas em cursor.

A propósito, vi na sua documentação que existem: opções responseTansformer e customFetch . Posso fazer algo com eles para obter as informações de paginação ??? Na verdade tentei muito, mas ainda sem sucesso ...:

https://www.apollographql.com/docs/link/links/rest/#response -transforming

https://www.apollographql.com/docs/link/links/rest/#custom -fetch

Infelizmente, apollo-link-rest depende da API de apollo-link para se conectar ao GraphQL - mas isso significa que não acho que haja uma maneira óbvia de compartilhar a API JS Headers diretamente - mas uma versão desnormalizada disso pode ser possível.

Dito isso, as opções responseTransformer ou customFetch podem ser usadas para corrigir o que você precisa.

O responseTransformer recebe o objeto JS Response que possui um atributo response.headers .

Então você pode escrever algo assim:

responseTransformer: async (resp: Response) => {
    const body = await resp.json();
    const interestingHeaders = {};
    interestingHeaders.headerOne = resp.headers.get("headerOne"); // Pluck out the headers you want
    body.__headers = interestingHeaders
    return body;
}

Dependendo da versão do seu navegador, você pode usar headers.entries() para obter todos os cabeçalhos como um objeto em vez de headers.get() - mas isso não está disponível atualmente no Safari-iOS.

Isso está obviamente simplificado e o tratamento de erros é deixado para você, mas acho que funcionaria!

customFetch também poderia fazer isso, mas acho que responseTransformer é mais fácil.

@fbartho Uau, isso é legal! Acabei de testar seu código, ele funciona e achei o link.

Agora vem outro problema, como posso acessar o body.__headers.link na consulta?

meu código de consulta é:

const queryTodos = gql`
  query Todos($page: number, $limit: number) {
    todos(_page: $page, _limit: $limit)
      @rest(type: "TodoPagination", path: "/todos/?{args}") {
      __headers {
        link
      }
      userId
      id
      title
      completed
    }
  }
`;

Mas qual valor de __headers é nulo ...
O código está aqui: Eu adicionei seu código em Client.ts e o código de consulta está em Todo.tsx :
https://codesandbox.io/s/how-to-access-response-0mqx7?file=/src/Todos.tsx

@fbartho Oi, tentei de três maneiras diferentes, enfim, resolvi esse problema enfim. No entanto, ainda tenho dúvidas se é uma boa solução. Você pode me dar sua opinião?

Método 1: falhou.
A princípio, acho que posso consultar __headers em useQuery() , tentei várias vezes, mas falhou.

Método 2: não tentei, porque duvido da solução
mude a estrutura da resposta em responseTransformer , coloque __headers em uma chave __headers e também coloque a lista de tarefas em uma chave todo . No entanto, acho que não é uma boa solução. Pois, toda a estrutura da resposta será alterada. Portanto, tenho que reescrever toda a estrutura em useQuery() .

Método 3: sucesso e muito simples
Coloquei __headers em uma variável reativa. Na função responseTransformer , eu apenas coloco o valor de __headers em uma variável reativa e a consulta após useQuery() executado. No entanto, ainda não tenho certeza, porque, tenho que fazer uma variável reativa diferente para consulta diferente ...

@blatoo , este é um problema antigo, que eu acabei de descobrir, resolvi com um new ApolloLink

const paginationLink = new ApolloLink((operation, forward) => {
  return forward(operation).map((response) => {
    const context = operation.getContext();

    const { headers } = context.restResponses[0] || null;
    // in my case i'm making a bunch of sub queries, so i'm using `[0]` to get the headers from the top level.

    if (headers) {
      const pagination = getPaginationFromHeaders(headers.get('link'));

      return { ...response, data: { ...response.data, pagination } };
    }
    return response;
  });
});

const client = new ApolloClient({
  cache: new InMemoryCache(),
  link: concat(paginationLink, restLink),
});
Esta página foi útil?
0 / 5 - 0 avaliações