大家好,
我想使用 apollo-link-rest 访问 rest api,但是,我无法按 useQuery() 访问response.headers
。
例如,一个带有分页的rest api,它将first, prev, next, last
信息放在标题中。 我怎样才能访问它?
我在这里做了一个例子: https :
您可以转到开发工具Network
选项卡,查看带有Headers的响应,在链接中,有分页信息。 但我不知道如何访问Headers
....
Hier 是我的主要代码,我不知道如何获得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 :
@blatoo - 不幸的是,这是 apollo-link-rest 中目前不存在的功能。
从根本上说,GraphQL 不希望处理 Headers —— 因为那些必须在图中的深处是可返回的。
如果有人想实现这一点,我可以看到我们在响应的“正文”中添加__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
依赖于apollo-link
的 API 来插入 GraphQL —— 但这意味着我认为没有明显的方法可以直接共享 JS Headers
API - 但它的非规范化版本可能是可能的。
也就是说, responseTransformer
或customFetch
选项可用于修补您需要的内容。
responseTransformer
接收具有response.headers
属性的 JS Response
对象。
所以你可以这样写:
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嗨,我尝试了三种不同的方式,最后,我终于解决了这个问题。 但是,我仍然怀疑这是否是一个好的解决方案。 你能给我一个你的意见吗?
方法一:失败。
起初,我想,我可以在useQuery()
查询__headers
useQuery()
,尝试了多次,但都失败了。
方法2:没试过,因为我怀疑解决方案
更改responseTransformer
响应的结构,将__headers
放在__headers
键中,并将待办事项列表放在todo
键中。 但是,我认为,这不是一个好的解决方案。 因为,响应的所有结构都会改变。 所以我必须重写useQuery()
所有结构。
方法三:成功与死简单
我把__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),
});