Hi an alle,
Ich möchte apollo-link-rest verwenden, um auf eine Rest-API zuzugreifen, jedoch kann ich nicht per useQuery() auf die response.headers
zugreifen.
Zum Beispiel eine Rest-API mit Paginierung, die die first, prev, next, last
Informationen in den Header einfügt. Wie kann ich darauf zugreifen?
Ich habe hier ein Beispiel gemacht: https://codesandbox.io/embed/how-to-access-response-0mqx7?file=/src/Client.ts
Sie können auf die Registerkarte Network
Entwicklungstools gehen, sehen Sie die Antwort mit Headers , im Link finden Sie die Paginierungsinformationen. Aber ich habe keine Ahnung, wie ich auf die Headers
zugreifen kann ....
Hier ist mein Hauptcode, ich habe keine Ahnung, wie ich die response.headers.link
bekomme ...
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>)
Ich habe diese Frage auch in Stackoverflow gestellt: https://stackoverflow.com/q/64791676/3279996 , falls Sie mehr Punkte in Stackoverflow wünschen. :D
@blatoo -- leider ist dies eine Funktion, die derzeit in apollo-link-rest nicht vorhanden ist.
Grundsätzlich erwartet GraphQL nicht, mit Headern umzugehen – da diese tief im Graphen zurückgegeben werden müssten.
Wenn jemand dies implementieren wollte, könnte ich mir vorstellen, dass wir __headers
als geheimes/automatisches Feld im "Text" einer Antwort hinzufügen, aber wir müssten ein Feature-Flag hinzufügen, um dieses Verhalten zu aktivieren, und Machen Sie etwas an den Header-Schlüsseln, damit sie graphql-kompatibel sind.
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 vielen Dank für diese Antwort. Es wäre ein tolles Feature, wenn wir auf die Header-Informationen zugreifen könnten. Ich benutze json-server, sie legen die Paginierungsinformationen in die Headers
, auch für die Cursor-basierten Paginierungsinformationen.
Übrigens habe ich in Ihrer Dokumentation gesehen, dass es folgende Optionen gibt: responseTansformer
und customFetch
. Kann ich etwas mit ihnen machen, um die Paginierungsinformationen zu erhalten??? Eigentlich habe ich viel probiert, aber immer noch kein Erfolg...:
https://www.apollographql.com/docs/link/links/rest/#response -transforming
https://www.apollographql.com/docs/link/links/rest/#custom -fetch
Leider verlässt sich apollo-link-rest
auf die API von apollo-link
, um sich in GraphQL einzubinden - aber das bedeutet, dass es meiner Meinung nach keinen offensichtlichen Weg gibt, die JS Headers
API direkt zu teilen -- aber eine denormalisierte Version davon könnte möglich sein.
Das heißt, die Optionen responseTransformer
oder customFetch
können verwendet werden, um das zu patchen, was Sie brauchen.
Das responseTransformer
empfängt das JS Response
Objekt, das ein response.headers
Attribut hat.
Du könntest also so etwas schreiben:
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;
}
Abhängig von Ihrer Browserversion können Sie möglicherweise headers.entries()
, um alle Header als ein Objekt zu erhalten, anstatt headers.get()
- aber das ist derzeit in Safari-iOS nicht verfügbar.
Dies ist offensichtlich vereinfacht und die Fehlerbehandlung bleibt Ihnen überlassen, aber ich denke, das würde funktionieren!
customFetch
könnte es auch tun, aber ich denke, responseTransformer
ist einfacher.
@fbartho Wow, das ist cool! Ich habe gerade deinen Code ausprobiert, er funktioniert und ich habe den Link bekommen.
Jetzt kommt ein weiteres Problem, wie kann ich auf die body.__headers.link
in der Abfrage zugreifen?
mein Abfragecode ist:
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
}
}
`;
Aber was ist der Wert von __headers
null...
Der Code ist hier: Ich habe Ihren Code in Client.ts
hinzugefügt und der Abfragecode ist in Todo.tsx
:
https://codesandbox.io/s/how-to-access-response-0mqx7?file=/src/Todos.tsx
@fbartho Hallo, ich habe drei verschiedene Möglichkeiten ausprobiert, endlich habe ich dieses Problem endlich gelöst. Ob das eine gute Lösung ist, bezweifle ich allerdings noch. Können Sie mir Ihre Meinung sagen?
Methode 1: fehlgeschlagen.
Zuerst denke ich, ich kann __headers
in useQuery()
abfragen, mehrmals versucht, aber fehlgeschlagen.
Methode 2: nicht versucht, weil ich die Lösung bezweifle
Ändern Sie die Struktur der Antwort in responseTransformer
, legen Sie __headers
in einen __headers
Schlüssel und auch die Aufgabenliste in einen todo
Schlüssel. Ich denke jedoch, dass es keine gute Lösung ist. Denn die gesamte Struktur der Antwort wird geändert. Also muss ich die gesamte Struktur in useQuery()
umschreiben.
Methode 3: Erfolg und ganz einfach
Ich habe __headers
in eine reaktive Variable geschrieben. In der Funktion responseTransformer
ich einfach den Wert von __headers
in eine reaktive Variable geschrieben und nach der Ausführung von useQuery()
abgefragt. Ich bin mir jedoch immer noch nicht sicher, da ich für verschiedene Abfragen eine andere reaktive Variable erstellen muss ...
@blatoo , dies ist ein älteres Problem, auf das ich selbst gerade new ApolloLink
gelöst habe
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),
});