Apollo-link-rest: Bagaimana cara mengakses response.headers dengan apollo-link-rest ?

Dibuat pada 11 Nov 2020  ·  6Komentar  ·  Sumber: apollographql/apollo-link-rest

Halo semua,

Saya ingin menggunakan apollo-link-rest untuk mengakses api istirahat, namun, saya tidak dapat per useQuery() mengakses response.headers .

Misalnya, rest api dengan pagination, yang menempatkan informasi first, prev, next, last di header. Bagaimana saya bisa mengakses itu?

Saya membuat contoh di sini: https://codesandbox.io/embed/how-to-access-response-0mqx7?file=/src/Client.ts

Anda dapat pergi ke tab develop tools Network , lihat responsnya dengan Header , di tautan , ada informasi pagination. Tapi saya tidak tahu, bagaimana cara mengakses Headers ....

Hier adalah kode utama saya, saya tidak tahu, bagaimana cara mendapatkan 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>)

Saya juga menanyakan pertanyaan ini di stackoverflow: https://stackoverflow.com/q/64791676/3279996 , jika Anda menghargai memiliki lebih banyak poin di stackoverflow. :D

enhancement enhancement💡 feature help wanted 🛠 question❔

Semua 6 komentar

@blatoo -- sayangnya, itu adalah fitur yang saat ini tidak ada di apollo-link-rest.

Pada dasarnya, GraphQL tidak berharap untuk berurusan dengan Header -- karena itu harus dikembalikan jauh di dalam grafik.

Jika seseorang ingin menerapkan ini, saya dapat melihat kami menambahkan __headers sebagai bidang rahasia/otomatis di "tubuh" respons, tetapi kami harus menambahkan flag fitur untuk mengaktifkan perilaku ini, dan lakukan beberapa mangling ke tombol header agar kompatibel dengan 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 terima kasih banyak atas jawaban ini. Ini akan menjadi fitur yang hebat, jika kita dapat mengakses informasi header. Saya menggunakan json-server, mereka meletakkan informasi pagination di Headers , juga untuk info pagination berbasis kursor.

Omong-omong, saya melihat di dokumentasi Anda ada: opsi responseTansformer dan customFetch . Dapatkah saya melakukan sesuatu dengan mereka untuk mendapatkan informasi pagination??? Sebenarnya saya sudah mencoba banyak, tetapi masih belum berhasil ...:

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

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

Sayangnya, apollo-link-rest bergantung pada apollo-link 's API untuk dihubungkan ke GraphQL -- tetapi ini berarti saya tidak berpikir ada cara yang jelas untuk membagikan JS Headers API secara langsung -- tetapi versi denormalisasi itu mungkin.

Yang mengatakan, opsi responseTransformer atau customFetch dapat digunakan untuk menambal apa yang Anda butuhkan.

responseTransformer menerima objek JS Response yang memiliki atribut response.headers .

Jadi Anda bisa menulis sesuatu seperti ini:

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

Tergantung pada versi browser Anda, Anda mungkin dapat menggunakan headers.entries() untuk mendapatkan semua header sebagai satu objek alih-alih headers.get() -- tetapi saat ini tidak tersedia di Safari-iOS.

Ini jelas disederhanakan, dan penanganan kesalahan diserahkan kepada Anda, tetapi saya pikir ini akan berhasil!

customFetch juga bisa, tapi menurut saya responseTransformer lebih mudah.

@fbartho Wow, ini keren! Saya baru saja mencoba kode Anda, itu berfungsi dan saya mendapatkan tautannya.

Sekarang muncul masalah lain, bagaimana saya bisa mengakses body.__headers.link dalam kueri?

kode kueri saya adalah:

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

Tapi apa nilai __headers adalah nol...
Kodenya ada di sini: Saya menambahkan kode Anda di Client.ts dan kode Kueri ada di Todo.tsx :
https://codesandbox.io/s/how-to-access-response-0mqx7?file=/src/Todos.tsx

@fbartho Hai, saya mencoba tiga cara berbeda, akhirnya, saya menyelesaikan masalah ini akhirnya. Namun, saya masih ragu, apakah itu solusi yang baik. Bisakah Anda memberi saya pendapat Anda?

Metode 1: gagal.
Pada awalnya, saya pikir, saya dapat menanyakan __headers di useQuery() , mencoba beberapa kali, tetapi gagal.

Metode 2: tidak mencoba, karena saya meragukan solusinya
ubah struktur respons di responseTransformer , masukkan __headers di kunci __headers dan juga masukkan daftar tugas di kunci todo . Namun, saya pikir, itu bukan solusi yang baik. Sebab, semua struktur respon akan berubah. Jadi saya harus menulis ulang semua struktur di useQuery() .

Metode 3: sukses dan sangat sederhana
Saya menempatkan __headers dalam variabel reaktif. Dalam fungsi responseTransformer , saya hanya memasukkan nilai __headers dalam variabel reaktif, dan menanyakannya setelah useQuery() dieksekusi. Namun, saya masih tidak yakin, karena, saya harus membuat variabel reaktif yang berbeda untuk kueri yang berbeda...

@blatoo , ini adalah masalah yang lebih lama, yang baru saja saya temui, menyelesaikannya dengan 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),
});
Apakah halaman ini membantu?
0 / 5 - 0 peringkat