Hola todos,
Quiero usar apollo-link-rest para acceder a una api de descanso, sin embargo, no puedo por useQuery () acceder a response.headers
.
Por ejemplo, una api de descanso con paginación, que coloca la información first, prev, next, last
en el encabezado. ¿Cómo puedo acceder a eso?
Hice un ejemplo aquí: https://codesandbox.io/embed/how-to-access-response-0mqx7?file=/src/Client.ts
Puede ir a la pestaña de herramientas de desarrollo Network
, ver la respuesta con Encabezados , en el enlace , está la información de paginación. Pero no tengo idea de cómo acceder a Headers
....
Hier es mi código principal, no tengo idea de cómo obtener el 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>)
También hice esta pregunta en stackoverflow: https://stackoverflow.com/q/64791676/3279996 , en caso de que aprecie tener más puntos en stackoverflow. :D
@blatoo : desafortunadamente, esa es una característica que no existe actualmente en apollo-link-rest.
Básicamente, GraphQL no espera lidiar con encabezados, porque tendrían que ser retornables en lo profundo del gráfico.
Si alguien quisiera implementar esto, podría vernos agregando __headers
como un campo secreto / automático en el "cuerpo" de una respuesta, pero tendríamos que agregar un indicador de función para habilitar este comportamiento, y haga algunos cambios en las teclas de encabezado para que sean compatibles con 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 muchas gracias por esta respuesta. Sería una gran característica si pudiéramos acceder a la información del encabezado. Yo uso json-server, ponen la información de paginación en Headers
, también para la información de paginación basada en el cursor.
Por cierto, vi en su documentación que hay: opciones responseTansformer
y customFetch
. ¿Puedo hacer algo con ellos para obtener la información de paginación ??? En realidad lo intenté mucho, pero aún no tuve éxito ...:
https://www.apollographql.com/docs/link/links/rest/#response -transforming
https://www.apollographql.com/docs/link/links/rest/#custom -fetch
Desafortunadamente, apollo-link-rest
basa en la API de apollo-link
para conectarse a GraphQL, pero esto significa que no creo que haya una forma obvia de compartir la API JS Headers
directamente - pero podría ser posible una versión desnormalizada.
Dicho esto, las opciones responseTransformer
o customFetch
podrían usarse para parchear lo que necesita.
El responseTransformer
recibe el objeto JS Response
que tiene un atributo response.headers
.
Entonces podrías escribir algo como esto:
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;
}
Dependiendo de la versión de su navegador, es posible que pueda usar headers.entries()
para obtener todos los encabezados como un solo objeto en lugar de headers.get()
, pero eso no está disponible actualmente en Safari-iOS.
Obviamente, esto está simplificado y el manejo de errores se deja a usted, ¡pero creo que esto funcionaría!
customFetch
también podría hacerlo, pero creo que responseTransformer
es más fácil.
@fbartho ¡ Vaya, esto es genial! Acabo de probar tu código, funciona y obtuve el enlace.
Ahora viene otro problema, ¿cómo puedo acceder a la consulta body.__headers.link
?
mi código de consulta es:
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
}
}
`;
Pero, ¿cuál es el valor de __headers
nulo ...
El código está aquí: agregué su código en Client.ts
y el código de consulta está en Todo.tsx
:
https://codesandbox.io/s/how-to-access-response-0mqx7?file=/src/Todos.tsx
@fbartho Hola, probé de tres formas diferentes, por fin, resolví este problema finalmente. Sin embargo, todavía dudo que sea una buena solución. ¿Puedes darme tu opinión?
Método 1: falló.
Al principio, creo que puedo consultar el __headers
en useQuery()
, lo intenté varias veces, pero fallé.
Método 2: no lo intenté, porque dudo de la solución
cambie la estructura de la respuesta en responseTransformer
, ponga __headers
en una tecla __headers
y también ponga la lista de tareas pendientes en una tecla todo
. Sin embargo, creo que no es una buena solución. Porque se cambiará toda la estructura de la respuesta. Entonces tengo que reescribir toda la estructura en useQuery()
.
Método 3: éxito y muerte simple
Pongo __headers
en una variable reactiva. En la función responseTransformer
, simplemente coloco el valor de __headers
en una variable reactiva y la consulto después de la ejecución de useQuery()
. Sin embargo, todavía no estoy seguro, porque tengo que hacer una variable reactiva diferente para una consulta diferente ...
@blatoo , este es un problema anterior, que yo mismo encontré, lo resolví con un 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),
});