Всем привет,
Я хочу использовать 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
@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),
});