본문 바로가기
개발 공부/GraphQL & Apollo Client

Apollo Client - Cache 기본 개념

by 호랭개발자 2021. 8. 27.
반응형

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한 것은 아니다 라고 적혀있다.

 

  1. 응답 데이터의 식별 가능한 모든 Object를 식별하여 식별된 각 Object마다 cache ID 생성
    기본적으로 ID는 __typename과 id 또는 _id 필드로 구성되어 __typename:id 형식을 띈다. 이 ID 형식은 사용자가 직접 지정할 수도 있다.
  2. 응답 데이터의 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

댓글