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