์๋ ํ์ธ์,
๋๋จธ์ง API์ ์ก์ธ์คํ๊ธฐ ์ํด apollo-link-rest๋ฅผ ์ฌ์ฉํ๊ณ ์ถ์ง๋ง useQuery () ๋น response.headers
์ก์ธ์ค ํ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, ํค๋์ first, prev, next, last
์ ๋ณด๋ฅผ ๋ฃ๋ ํ์ด์ง ๋งค๊น์ด์๋ ๋๋จธ์ง API์
๋๋ค. ์ด๋ป๊ฒ ์ก์ธ์ค ํ ์ ์์ต๋๊น?
์ฌ๊ธฐ์ ์์ ๋ฅผ ๋ง๋ค์์ต๋๋ค : https://codesandbox.io/embed/how-to-access-response-0mqx7?file=/src/Client.ts
๊ฐ๋ฐ ๋๊ตฌ Network
ํญ์ผ๋ก ์ด๋ํ์ฌ ํค๋๊ฐ ์๋ ์๋ต ์ ๋ณผ ์ ์์ต๋๋ค. ๋งํฌ ์ ํ์ด์ง ๋งค๊น ์ ๋ณด๊ฐ ์์ต๋๋ค. ํ์ง๋ง 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://stackoverflow.com/q/64791676/3279996 ์์์ด ์ง๋ฌธ์ํ์ต๋๋ค. :๋
@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
๋ GraphQL์ ์ฐ๊ฒฐํ๊ธฐ ์ํด apollo-link
์ API์ ์์กดํฉ๋๋ค.ํ์ง๋ง ์ด๊ฒ์ 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.get()
๋์ headers.entries()
๋ฅผ ์ฌ์ฉํ์ฌ ๋ชจ๋ ํค๋๋ฅผ ํ๋์ ๊ฐ์ฒด๋ก ๊ฐ์ ธ์ฌ ์ ์์ง๋ง ํ์ฌ 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
์ด null ์ธ ๊ฒ์ ...
์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. Client.ts
์ฝ๋๋ฅผ ์ถ๊ฐํ๊ณ ์ฟผ๋ฆฌ ์ฝ๋๋ Todo.tsx
.
https://codesandbox.io/s/how-to-access-response-0mqx7?file=/src/Todos.tsx
@fbartho ์๋ ํ์ธ์, ์ ๋ ์ธ ๊ฐ์ง ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์๋ํ์ต๋๋ค. ๋๋์ด์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ต๋๋ค. ๊ทธ๋ฌ๋ ๋๋ ๊ทธ๊ฒ์ด ์ข์ ํด๊ฒฐ์ฑ ์ธ์ง ์ฌ์ ํ ์๋ฌธ์ด๋ค. ๋์๊ฒ ๋น์ ์ ์๊ฒฌ์ ์ค ์ ์์ต๋๊น?
๋ฐฉ๋ฒ 1 : ์คํจํ์ต๋๋ค.
์ฒ์์๋ __headers
์์ useQuery()
__headers
์ฟผ๋ฆฌ๋ฅผ ์ฌ๋ฌ ๋ฒ ์๋ํ์ง๋ง ์คํจํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
๋ฐฉ๋ฒ 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),
});