앞선 apollo-client
세팅 방법 포스팅에서 클라이언트 서버를 생성하고 React
앱과 연동하였다.
개발을 하다보면 여기 구조를 바꿔야할 때가 있는데, 그 중 하나가 JsonWebToken (JWT)
를 사용할 때 로그인 후 토큰을 발급 받고 이후 요청을 보낼 때 요청 해더에 authorization
정보를 헤더에 포함해 주는게 일반적인데, 이를 위해서는 main.ts
구조를 변경해야 한다.
import { setContext } from "@apollo/client/link/context";
const authLink = setContext((_, { headers }) => {
// server로 부터 발급 받은 토큰 가져오기
const accessToken = store.getState().authToken.accessToken;
return {
headers: {
...headers,
authorization: accessToken ? `Bearer ${accessToken}` : "",
}
}
});
apollo-client
에 내부적으로 요청의 context
를 수정할 수 있는 setContext
함수를 제공한다.
이 함수를 사용하여 헤더를 설정해주면 된다. 위에서 store.getState()
부분은 redux
에 토큰을 저장해 두었을 때를 예시로 든 것이고 토큰을 가져와서 헤더에 설정만 해주면 된다.
const authLink = setContext((_, { headers }) => {
// server로 부터 발급 받은 토큰 가져오기
const accessToken = store.getState().authToken.accessToken;
return {
headers: {
...headers,
authorization: accessToken ? `Bearer ${accessToken}` : "",
}
}
});
// Apollo의 concat 기능으로 합쳐준다
const link = ApolloLink.from([authLink.concat(httpLink)])
const client = new ApolloClient({
link: link,
cache: new InMemoryCache(),
defaultOptions: {
watchQuery: {
fetchPolicy: 'cache-and-network',
},
},
});
const rootElement = document.getElementById('root');
if (!rootElement) throw new Error('Failed to find the root element');
const root = ReactDOM.createRoot(rootElement);
root.render(
<Provider store={store}>
<ApolloProvider client={client}>
<BrowserRouter>
<App />
</BrowserRouter>
</ApolloProvider>
</Provider>
)
이렇게 설정을 해두면 httpLink
에 위의 setContext
함수를 통해 추가한 헤더 설정을 적용이 된다. 위 설정을 적용하면 useQuery
와 useMutation
을 사용할 때마다 일괄적으로 헤더설정이 추가된다. 만약 특정 쿼리에만 헤더설정을 하고 싶다면 해당 useQuery
또는 useMutation
에 헤더설정을 추가해야 한다.
또한 위 설정은 일괄적으로 쿼리에 적용된다는 점에서 middleware
같은 역할을 할 수도 있는데 예를 들어 쿼리에 어떤 응답이 왔을 때의 동작을 정의하여 적용하고 싶다면 아래와 같이 추가해 줄수 있다.
import { onError } from "@apollo/client/link/error";
import { handleGraphQLError } from './handlers/GraphQLErrorHandlers.tsx';
// 에러 발생시 동작 정의
const errorLink = onError((err: any) => {
if (err.graphQLErrors) {
handleGraphQLError(err);
}
})
const link = ApolloLink.from([errorLink, authLink.concat(httpLink)])