Apollo Client에서는 GraphQL 쿼리의 응답 내용을 구조화시켜 로컬 InMemoryCache에 저장한다. 이를 통해 서버에서 응답을 받기 전에 캐시를 참조해 데이터를 받아오는 등의 기능이 가능하기 때문에 서버와의 통신 없이도 쿼리 응답을 받을 수 있어 좀 더 빠른 응답을 받을 수 있다.
👀 Cache를 어떻게 저장할까?
Apollo Client의 InMemoryCache는 flat lookup table를 가지고 있는데 이 테이블은 각 Object의 참조값을 가지고 있어 이를 통해 각 object를 찾아갈 수 있다. 응답 데이터의 hierarchical한 구조를 flat한 lookup table에 저장하기 위해 아래와 같은 구조화의 과정을 거친다.
참고) Apollo Client의 공식 문서에는 cache ID를 생성할 수 없는 Object는 부모 Object 안에 바로 caching 되고 부모 Object를 통해서 참조될 수 있는데 이러한 경우로 인해 cache가 항상 완전히 flat한 것은 아니다 라고 적혀있다.
- 응답 데이터의 식별 가능한 모든 Object를 식별하여 식별된 각 Object마다 cache ID 생성
기본적으로 ID는 __typename과 id 또는 _id 필드로 구성되어 __typename:id 형식을 띈다. 이 ID 형식은 사용자가 직접 지정할 수도 있다. - 응답 데이터의 object 필드를 위에서 생성된 cache ID를 사용한 참조로 대체
query getPerson($id: Int!){
persons(where: {id: {equals: $id}}){
id
name
Location{
id
locationName
}
Gender{
id
genderName
}
}
}
위와 같은 쿼리를 보내 서버로부터 응답을 받아온다고 하자.
{
"data": {
"Person": {
"__typename": "Person"
"id": 225
"name": "Gildong Hong"
"Location": {
"__typename" : "Location"
"id": 1
"locationName": "Seoul"
}
"Gender": {
"__typename": "Gender",
"id": 1,
"genderName": "Male"
}
}
}
}
위의 응답에서 식별 가능한 객체는 Person, Location, Gender 이다. 따라서 InMemoryCache의 flat lookup table에는 Person:225, Location:1, Gender:1 이렇게 세 개의 cache ID가 저장된다. 정규화된 데이터는 아래와 같은 형태를 가진다.
{
"Person": {
"__typename": "Person",
"id": 225,
"name": "Gildong Hong",
"Location": {
"__ref": "Location:1"
}
"Gender": {
"__ref": "Gender:1"
}
}
}
Apollo client는 객체 뿐 아니라 쿼리도 캐싱하기 때문에 variable을 통해 캐시에 있는 각 쿼리에 접근할 수 있다. Lookup table은 Apollo Client Devtools 에서 확인 가능하며 아래와 비슷하게 생겼다.
(이는 직접 Apollo Client Devtools를 사용해 눈으로 보는 것이 이해가 더 빠를 것이다.)
ROOT_QUERY
persons(id:225): [Person] // 응답 데이터가 Person 객체의 Array라는 의미
...
Person:225
__typename: Person,
id: 225,
name: Gildong Hong,
Location:
__ref: Location:1
Gender:
__ref: Gender:1
Location:1
__typename: Location,
id: 1,
locationName: Seoul
Gender:1
__typename: Gender
id: 1,
genderName: Male
👀 CacheOptions (fetchPolicy)
캐시의 동작 방법을 선택하기 위해 InMemoryCache 생성자에서 fetchPolicy를 설정할 수 있다. fetchPolicy는 각 쿼리에서도 설정이 가능하다. Default 값은 cache-first이다.
- cache-first
항상 캐시를 먼저 확인한다. 캐시에 요청한 데이터가 있는 경우 캐시 데이터를 반환하고, 없는 경우 서버에 요청을 보내 응답 데이터를 캐시에 저장하고 데이터를 반환한다. - cache-only
요청한 데이터가 캐시에 있는지 확인하고 없으면 에러를 반환한다. - cache-and-network
캐시 확인과 서버 요청이 모두 발생한다. 요청한 데이터가 캐시에 있는 경우 일단 캐시 데이터를 반환한다. 서버의 응답 데이터가 캐시에 저장되어 있는 데이터와 다를 경우 캐시를 업데이트하고 데이터를 반환한다. - network-only
캐시 확인 없이 서버에 요청을 보낸다. 캐시를 사용하지 않지만 응답 데이터는 캐시에 저장된다. - no-cache
network-only 방법과 비슷하지만 이 방법에서는 응답 데이터를 캐시에 저장하지 않는다.
fetchPolicy는 캐시를 업데이트하는 방법 가운데 하나이다. 이 외에도 mutation 실행 후 refetch하는 방법과 직접 캐시를 수정하는 방법도 존재한다.
'개발 공부 > GraphQL & Apollo Client' 카테고리의 다른 글
Apollo Client - Cache 사용하기 (0) | 2022.08.14 |
---|
댓글