Apollo-link-rest: ¿Cómo acceder a response.headers con apollo-link-rest?

Creado en 11 nov. 2020  ·  6Comentarios  ·  Fuente: apollographql/apollo-link-rest

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

enhancement enhancement💡 feature help wanted 🛠 question❔

Todos 6 comentarios

@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),
});
¿Fue útil esta página
0 / 5 - 0 calificaciones