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