Apollo-link-rest: Comment accéder à response.headers avec apollo-link-rest ?

Créé le 11 nov. 2020  ·  6Commentaires  ·  Source: apollographql/apollo-link-rest

Salut tout le monde,

Je veux utiliser apollo-link-rest pour accéder à une API de repos, cependant, je ne peux pas par useQuery() accéder au response.headers .

Par exemple, une API de repos avec pagination, qui place les informations first, prev, next, last dans l'en-tête. Comment puis-je accéder à cela?

J'ai fait un exemple ici : https://codesandbox.io/embed/how-to-access-response-0mqx7?file=/src/Client.ts

Vous pouvez aller dans l'onglet outils de développement Network , voir la réponse avec les en- têtes , dans le lien , il y a les informations de pagination. Mais je n'ai aucune idée de comment accéder au Headers ....

Hier est mon code principal, je n'ai aucune idée de comment obtenir le 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>)

J'ai également posé cette question dans stackoverflow: https://stackoverflow.com/q/64791676/3279996 , au cas où vous apprécieriez d'avoir plus de points dans stackoverflow. :RÉ

enhancement enhancement💡 feature help wanted 🛠 question❔

Tous les 6 commentaires

@blatoo -- malheureusement, c'est une fonctionnalité qui n'existe pas actuellement dans apollo-link-rest.

Fondamentalement, GraphQL ne s'attend pas à traiter les en-têtes, car ceux-ci devraient pouvoir être renvoyés profondément dans le graphique.

Si quelqu'un voulait implémenter cela, je pourrais nous voir ajouter __headers tant que champ secret/automatique dans le "corps" d'une réponse, mais nous devrons ajouter un indicateur de fonctionnalité pour activer ce comportement, et modifiez les clés d'en-tête afin qu'elles soient compatibles 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 merci beaucoup pour cette réponse. Ce serait une excellente fonctionnalité si nous pouvions accéder aux informations d'en-tête. J'utilise json-server, ils mettent les informations de pagination dans le Headers , également pour les informations de pagination basées sur le curseur.

D'ailleurs, j'ai vu dans votre documentation qu'il y a : les options responseTansformer et customFetch . Puis-je faire quelque chose avec eux pour obtenir les informations de pagination ??? En fait, j'ai beaucoup essayé, mais toujours sans succès... :

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

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

Malheureusement, apollo-link-rest s'appuie sur l'API de apollo-link pour se connecter à GraphQL -- mais cela signifie que je ne pense pas qu'il existe un moyen évident de partager directement l'API JS Headers - mais une version dénormalisée de celui-ci pourrait être possible.

Cela dit, les options responseTransformer ou customFetch peuvent être utilisées pour corriger ce dont vous avez besoin.

Le responseTransformer reçoit l'objet JS Response qui a un attribut response.headers .

Vous pourriez donc écrire quelque chose comme ceci :

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;
}

Selon la version de votre navigateur, vous pourrez peut-être utiliser headers.entries() pour obtenir tous les en-têtes en un seul objet au lieu de headers.get() -- mais ce n'est actuellement pas disponible dans Safari-iOS.

C'est évidemment simplifié, et la gestion des erreurs est laissée à vous, mais je pense que cela fonctionnerait !

customFetch pourrait aussi le faire, mais je pense que responseTransformer est plus facile.

@fbartho Wow, c'est cool ! Je viens d'essayer ton code, ça marche et j'ai le lien.

Maintenant, il y a un autre problème, comment puis-je accéder au body.__headers.link en requête ?

mon code de requête est :

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
    }
  }
`;

Mais qu'est-ce que la valeur du __headers est nulle...
Le code est ici : j'ai ajouté votre code en Client.ts et le code de la requête est en Todo.tsx :
https://codesandbox.io/s/how-to-access-response-0mqx7?file=/src/Todos.tsx

@fbartho Salut, j'ai essayé trois manières différentes, enfin, j'ai enfin résolu ce problème. Cependant, je doute encore que ce soit une bonne solution. Pouvez-vous me donner votre avis ?

Méthode 1 : échec.
Au début, je pense que je peux interroger le __headers dans useQuery() , essayé plusieurs fois, mais a échoué.

Méthode 2: n'a pas essayé, car je doute de la solution
changez la structure de la réponse dans responseTransformer , mettez le __headers dans une clé __headers et mettez également la liste de tâches dans une clé todo . Cependant, je pense que ce n'est pas une bonne solution. Car, toute la structure de la réponse sera modifiée. Je dois donc réécrire toute la structure en useQuery() .

Méthode 3 : le succès et la simplicité
J'ai mis le __headers dans une variable réactive. Dans la fonction responseTransformer , je viens de mettre la valeur de __headers dans une variable réactive et de l'interroger après l'exécution du useQuery() . Cependant, je ne suis toujours pas sûr, car je dois créer une variable réactive différente pour une requête différente ...

@blatoo , c'est un problème plus ancien, que je viens de rencontrer moi-même, je l'ai résolu avec 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),
});
Cette page vous a été utile?
0 / 5 - 0 notes