Apollo-link-rest: Как получить доступ к response.headers с помощью apollo-link-rest?

Созданный на 11 нояб. 2020  ·  6Комментарии  ·  Источник: apollographql/apollo-link-rest

Всем привет,

Я хочу использовать apollo-link-rest для доступа к api rest, однако я не могу использовать useQuery () для доступа к response.headers .

Например, rest api с разбивкой на страницы, которые помещают информацию first, prev, next, last в заголовок. Как я могу получить к нему доступ?

Я привел здесь пример: https://codesandbox.io/embed/how-to-access-response-0mqx7?file=/src/Client.ts

Вы можете перейти на вкладку инструментов разработки Network , увидеть ответ с заголовками , в ссылке есть информация о разбиении на страницы. Но я понятия не имею, как получить доступ к Headers ....

Вот мой основной код, я понятия не имею, как получить 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>)

Я также задал этот вопрос в stackoverflow: https://stackoverflow.com/q/64791676/3279996 , если вы цените больше очков в stackoverflow. : D

enhancement enhancement💡 feature help wanted 🛠 question❔

Все 6 Комментарий

@blatoo - к сожалению, этой функции пока нет в apollo-link-rest.

По сути, GraphQL не предполагает иметь дело с заголовками, потому что они должны возвращаться глубоко в графе.

Если бы кто-то захотел реализовать это, я мог бы увидеть, как мы добавляем __headers в качестве секретного / автоматического поля в «теле» ответа, но нам нужно было бы добавить флаг функции, чтобы включить это поведение, и немного измените ключи заголовка, чтобы они были совместимы с 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 большое спасибо за этот ответ. Было бы здорово, если бы мы могли получить доступ к информации заголовка. Я использую json-server, они помещают информацию о разбиении на страницы в Headers , также для информации о разбиении на страницы на основе курсора.

Кстати, я видел в вашей документации: responseTansformer и customFetch варианты. Могу я что-нибудь с ними сделать, чтобы получить информацию о нумерации страниц ??? На самом деле я очень много пробовал, но безуспешно ...:

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

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

К сожалению, apollo-link-rest полагается на API apollo-link для подключения к GraphQL - но это означает, что я не думаю, что существует очевидный способ напрямую поделиться JS Headers API - но возможна денормализованная версия.

Тем не менее, параметры responseTransformer или customFetch могут быть использованы для исправления того, что вам нужно.

responseTransformer получает объект JS Response который имеет атрибут response.headers .

Итак, вы могли бы написать что-то вроде этого:

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

В зависимости от версии вашего браузера вы можете использовать headers.entries() для получения всех заголовков как одного объекта вместо headers.get() но в настоящее время это недоступно в Safari-iOS.

Это, очевидно, упрощено, и обработка ошибок предоставлена ​​вам, но я думаю, что это сработает!

customFetch тоже может это сделать, но я думаю, что responseTransformer проще.

@fbartho Вау, это круто! Я просто попробовал ваш код, он работает, и я получил ссылку.

Теперь возникает еще одна проблема: как я могу получить доступ к body.__headers.link в запросе?

мой код запроса:

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

Но какое значение __headers равно нулю ...
Код здесь: я добавил ваш код в Client.ts а код запроса - в Todo.tsx :
https://codesandbox.io/s/how-to-access-response-0mqx7?file=/src/Todos.tsx

@fbartho Привет, я попробовал три разных способа, наконец-то я решил эту проблему. Однако я все еще сомневаюсь, что это хорошее решение. Вы можете высказать свое мнение?

Метод 1: не удалось.
Сначала я думаю, что могу запросить __headers в useQuery() , пробовал несколько раз, но потерпел неудачу.

Способ 2: не пробовал, потому что сомневаюсь в решении
измените структуру ответа в responseTransformer , поместите __headers в ключ __headers а также поместите список задач в ключ todo . Однако я считаю, что это не очень хорошее решение. Потому что изменится вся структура ответа. Поэтому мне нужно переписать всю структуру в useQuery() .

Метод 3: успех и мертвая простота
Я помещаю __headers в реактивную переменную. В функции responseTransformer я просто помещаю значение __headers в реактивную переменную и запрашиваю его после выполнения useQuery() . Однако я все еще не уверен, потому что мне нужно создать другую реактивную переменную для другого запроса ...

@blatoo , это более старая проблема, с которой я сам только что столкнулся, решил ее с помощью 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),
});
Была ли эта страница полезной?
0 / 5 - 0 рейтинги