Apollo-link-rest: Wie greife ich mit apollo-link-rest auf response.headers zu?

Erstellt am 11. Nov. 2020  ·  6Kommentare  ·  Quelle: apollographql/apollo-link-rest

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

enhancement enhancement💡 feature help wanted 🛠 question❔

Alle 6 Kommentare

@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),
});
War diese Seite hilfreich?
0 / 5 - 0 Bewertungen