#4-1 GraphQL Pagination, Caching > 앱개발

매출이 오르면 내리는 수수료! 지금 수수료센터에서 전자결제(PG)수수료 비교견적 신청해 보세요!

앱개발

#4-1 GraphQL Pagination, Caching 정보

#4-1 GraphQL Pagination, Caching

본문

Pagination

 

다른 페이지 매김 모델은 다른 클라이언트 기능을 가능하게합니다.
GraphQL의 일반적인 사용 사례는 객체 세트 간의 관계를 가로 지르는 것입니다. GraphQL에서 이러한 관계를 노출 할 수있는 다양한 방법이 있으며, 클라이언트 개발자에게 다양한 기능을 제공합니다.
Plurals

 

객체 간의 연결을 노출하는 가장 간단한 방법은 복수형을 반환하는 필드를 사용하는 것입니다. 예를 들어, R2-D2의 친구 목록을 얻고 싶다면 모든 것을 요청할 수 있습니다.

 

 {

  "data": {

    "hero": {

      "name": "R2-D2",

      "friends": [

        {

          "name": "Luke Skywalker"

        },

        {

          "name": "Han Solo"

        },

        {

          "name": "Leia Organa"

        }

      ]

    }

  }

}

Slicing

빨리, 그러나, 우리는 클라이언트가 원할지도 모른 추가적인 행동이라는 것을 깨닫습니다. 클라이언트는 가져올 친구를 몇 명 지정할 수 있기를 원할 수 있습니다. 어쩌면 처음 두 개만 원할 수도 있습니다. 그래서 우리는 다음과 같은 것을 폭로하고 싶습니다.

{
  hero {
    name
    friends(first:2) {
      name
    }
  }
}

그러나 처음 두 개를 가져온 경우 목록을 통해 페이지 매기기를 원할 수 있습니다. 클라이언트가 처음 두 친구를 가져 오면 두 번째 친구에게 다음 두 친구를 요청할 수 있습니다. 어떻게 하면 그 행동을 가능하게 할 수 있을까요? 

Pagination and Edges

페이지 매김을 할 수있는 방법에는 여러 가지가 있습니다. 

 

  • 우리는 친구들과 같은 일을 할 수 있습니다 (처음에는 2 오프셋 : 2).
  • 우리는 친구와 같은 일을 할 수 있습니다 (첫 번째: 2 후: $ friendId). 우리가 가져온 마지막 친구가 다음 두 사람을 요구할 수 있습니다.
  • 우리는 친구와 같은 것을 할 수 있습니다 (첫 번째: 2 후: $ friendCursor). 마지막 항목에서 커서를 가져 와서 페이지 매김에 사용합니다.

 

일반적으로 커서 기반 페이지 매김은 가장 강력하게 설계된 것입니다. 특히 커서가 불투명한 경우 커서 기반의 페이지 매김 (커서를 오프셋 또는 ID로 지정)을 사용하여 오프셋 또는 ID 기반 페이지 매김을 구현할 수 있으며, 커서를 사용하면 향후 페이지 매김 모델이 변경 될 경우 추가적인 유연성이 제공됩니다. 커서가 불투명하고 형식을 사용하지 말아야한다는 것을 상기시켜주기 위해 base64 인코딩을 제안합니다. 

그것은 우리를 문제로 인도합니다. 그래도; 객체에서 어떻게 커서를 가져 옵니까? 우리는 커서가 사용자 유형에 존재하는 것을 원하지 않을 것입니다. 그것은 객체가 아닌 연결의 속성입니다. 따라서 우리는 새로운 간접 계층을 도입하고자 할 수 있습니다. 우리 친구들 필드는 우리에게 가장자리 목록을 주어야하

며 가장자리에는 커서와 기본 노드가 있습니다.

{
  hero {
    name
    friends(first:2) {
      node {
        name
      }
      cursor
    }
  }
}

가장자리의 개념은 객체 중 하나가 아니라 가장자리에 특정한 정보가있는 경우 유용합니다. 예를 들어 API에서 '우정의 시간'을 폭로하고 싶다면 가장자리에 살게하는 것이 자연스러운 장소입니다. 

End-of-list, counts, and Connections

이제 우리는 커서를 사용하여 연결을 페이지 매김하는 기능을 가지고 있지만 연결이 언제 끝났는지 어떻게 알 수 있습니까? 빈 목록을 얻을 때까지 계속 쿼리해야하지만 추가 요청이 필요하지 않으므로 연결이 끝나면 연결을 알려주고 싶습니다. 마찬가지로 연결 자체에 대한 추가 정보를 알고 싶다면 어떻게해야합니까? 예를 들어 R2-D2에는 몇 명의 친구가 있습니까? 

이 두 가지 문제를 해결하기 위해 friends 필드는 연결 객체를 반환할 수 있습니다. 그런 다음 연결 개체에는 가장자리에 대한 필드뿐만 아니라 다른 정보 (예: 총 개수 및 다음 페이지의 존재 여부에 대한 정보)가 있습니다. 그래서 우리의 최종 질의는 다음과 같이 보일 것입니다. 

{
  hero {
    name
    friends(first:2) {
      totalCount
      edges {
        node {
          name
        }
        cursor
      }
      pageInfo {
        endCursor
        hasNextPage
      }
    }
  }
}

이 PageInfo 객체에는 endCursor 및 startCursor도 포함될 수 있습니다. 이런 식으로 edge가 포함하고있는 추가 정보가 필요 없다면 pageInfo에서 페이지 매김에 필요한 커서를 얻었 기 때문에 가장자리를 쿼리 할 필요가 없습니다. 이로 인해 연결에 대한 가용성이 향상 될 수 있습니다. 가장자리 목록을 표시하는 대신 간접적 인 계층을 피하기 위해 노드 목록 만 표시 할 수도 있습니다. 

Complete Connection Model

분명히, 이것은 단지 복수형을 갖는 독창적 인 디자인보다 더 복잡합니다! 그러나이 디자인을 채택함으로써 우리는 클라이언트를위한 많은 기능을 사용할 수있게되었습니다. 

 

  • 목록을 페이지 매김하는 기능.
  • totalCount 또는 pageInfo와 같은 연결 자체에 대한 정보를 요청하는 기능.
  • cursor 또는 friendshipTime과 같은 가장자리 자체에 대한 정보를 요청하는 기능.
  • 사용자가 불투명 한 커서를 사용하기 때문에 백엔드가 페이지 매김을 수행하는 방식을 변경할 수 있습니다.

 

이를 실제로 보기 위해 friendsConnection이라는 예제 스키마에 이러한 모든 개념을 노출하는 추가 필드가 있습니다. 예제 쿼리에서 확인할 수 있습니다. friendConnection에 after 매개 변수를 제거하여 페이지 매김이 어떻게 영향을 받는지보십시오. 또한 가장자리 필드를 연결의 도우미 친구 필드로 바꾸십시오. 그러면 클라이언트에 적합한 경우 간접적인 추가 가장자리 레이어없이 친구 목록에 직접 액세스 할 수 있습니다. 

{

  hero {

    name

    friendsConnection(first:2 after:"Y3Vyc29yMQ==") {

      totalCount

      edges {

        node {

          name

        }

        cursor

      }

      pageInfo {

        endCursor

        hasNextPage

      }

    }

  }

}

{

  "data": {

    "hero": {

      "name": "R2-D2",

      "friendsConnection": {

        "totalCount": 3,

        "edges": [

          {

            "node": {

              "name": "Han Solo"

            },

            "cursor": "Y3Vyc29yMg=="

          },

          {

            "node": {

              "name": "Leia Organa"

            },

            "cursor": "Y3Vyc29yMw=="

          }

        ],

        "pageInfo": {

          "endCursor": "Y3Vyc29yMw==",

          "hasNextPage": false

        }

      }

    }

  }

}

Caching

객체 식별자를 제공하면 클라이언트가 풍부한 캐시를 구축 할 수 있습니다. 

 

엔드 포인트 기반 API에서 클라이언트는 HTTP 캐싱을 사용하여 자원 재 패치를 쉽게 피하고 두 자원이 동일한 시기를 식별할 수 있습니다. 이 API의 URL은 클라이언트가 캐시를 작성하는 데 사용할 수 있는 전 세계적으로 고유 한 식별자입니다. 그래도 GraphQL에는 주어진 객체에 대해 전역적으로 고유한 식별자를 제공하는 URL과 같은 프리미티브가 없습니다. 그러므로 API가 클라이언트가 사용할 수 있도록 이러한 식별자를 노출하는 것이 가장 좋습니다. 


Globally Unique IDs

가능한 한 가지 패턴은 id와 같은 필드를 전역적으로 고유한 식별자로 예약하는 것입니다. 이 문서 전체에 사용 된 예제 스키마는이 접근 방식을 사용합니다. 

 

{

  starship(id:"3003") {

    id

    name

  }

  droid(id:"2001") {

    id

    name

    friends {

      id

      name

    }

  }

}

{

  "data": {

    "starship": {

      "id": "3003",

      "name": "Imperial shuttle"

    },

    "droid": {

      "id": "2001",

      "name": "R2-D2",

      "friends": [

        {

          "id": "1000",

          "name": "Luke Skywalker"

        },

        {

          "id": "1002",

          "name": "Han Solo"

        },

        {

          "id": "1003",

          "name": "Leia Organa"

        }

      ]

    }

  }

}

이것은 클라이언트 개발자에게 넘겨 줄 강력한 도구입니다. 자원 기반 API의 URL이 전역 고유 키를 제공하는 것과 같은 방식으로 이 시스템의 id 필드는 전역 적으로 고유한 키를 제공합니다. 


백엔드가 식별자에 UUID와 같은 것을 사용한다면,이 전역적으로 고유한 ID를 노출하는 것은 매우 간단 할 수 있습니다! 백엔드에 이미 모든 개체에 대한 전역 고유 ID가 없는 경우 GraphQL 계층에서 이를 구성해야 할 수 있습니다. 종종 ID에 유형 이름을 추가하고 이를 식별자로 사용하는 것만큼 간단합니다. 그런 다음 서버는 base64 인코딩을 통해 해당 ID를 불투명하게 만들 수 있습니다. 

Compatibility with existing APIs

이 목적을 위해 id 필드를 사용하는 것에 대한 한 가지 우려는 GraphQL API를 사용하는 클라이언트가 기존 API와 함께 작동하는 방법입니다. 예를 들어 기존 API가 유형별 ID를 허용했지만 GraphQL API가 전역 고유 ID를 사용하는 경우 두 API를 동시에 사용하는 것은 까다로운 작업 일 수 있습니다.

 

이러한 경우 GraphQL API는 이전 API의 ID를 별도의 필드에 표시 할 수 있습니다. 이것은 우리에게 두 세계의 장점을 제공합니다. 

 

  • GraphQL 클라이언트는 계속적으로 전역 고유 ID를 얻기위한 일관된 메커니즘에 의존 할 수 있습니다.
  • 이전 API로 작업해야 하는 클라이언트는 객체에서 previousApiId를 가져 와서 사용할 수도 있습니다.

 

Alternatives 

전 세계적으로 고유한 ID가 과거에는 강력한 패턴으로 입증되었지만 사용할 수 있는 유일한 패턴이 아니며 모든 상황에 적합한 패턴도 아닙니다. 클라이언트가 필요로하는 정말로 중요한 기능은 캐싱에 대해 전역으로 고유 한 식별자를 파생시킬 수 있는 기능입니다. 서버에서 ID를 파생 시키면 클라이언트가 단순화되지만 클라이언트는 식별자를 파생시킬 수도 있습니다. 종종 이것은 (__typename으로 쿼리 된) 객체의 유형을 일부 유형 고유 식별자와 결합하는 것처럼 간단합니다. 

 

또한 기존 API를 GraphQL API로 대체하는 경우 GraphQL의 모든 입력란이 전 세계적으로 고유하게 변경된 ID를 제외하고 동일하면 혼동을 줄 수 있습니다. 이것이 세계 유일 필드로 ID를 사용하지 않기로 결정한 또 다른 이유입니다. 

 

 

공감
0

댓글 0개

전체 756 |RSS
앱개발 내용 검색

회원로그인

(주)에스아이알소프트 / 대표:홍석명 / (06211) 서울특별시 강남구 역삼동 707-34 한신인터밸리24 서관 1404호 / E-Mail: admin@sir.kr
사업자등록번호: 217-81-36347 / 통신판매업신고번호:2014-서울강남-02098호 / 개인정보보호책임자:김민섭(minsup@sir.kr)
© SIRSOFT