🏂

【GraphQL】複数のフィールドを組み合せがユニークなtypeのApollo cacheについて検証した【Tip!】

2023/08/09に公開1

apollo clientはデフォルトでtypename:idをキャッシュIDとして対応付ける形で、キャッシュを保存しますが、

By default, an object's cache ID is the concatenation of the object's
__typename and id (or _id) fields, separated by a colon (:).

https://www.apollographql.com/docs/react/caching/overview/#2-generate-cache-ids

type Student {
class: string!
number: int!
name: string!
}

上記スキーマを確認すると、idフィールドが存在しないので、
通常とは違い、
typename:idをキャッシュIDとして、キャッシュを保存ができません。

そのため、apolloで個々のstudentをキャッシュするために以下のように設定を行うことができます。

結論

classとnumber(出席)の組み合わせはuniqueとなるので、
classとnumberをもとにキャッシュIDを構成する方針を取ります。

※uniqueの例
学校で青組の出席番号1の生徒は唯一。

class:青組 number:1
class:赤組 number:1 

DynamoDBだとclassがPKで、numberがSKで、プライマリーキーが構成されているようなイメージ。

具体的には

アポロクライアント生成時に、keyFieldオプションに、classとnumberを指定して完了です。

const client = new ApolloClient({
  uri: "apiエンドポイント",
  cache: new InMemoryCache({
    typePolicies: {
      Student: {
        keyFields: ["class", "number"],
      },
      Query: {

試しにStudentを取得するクエリを叩いて、InMemoryCacheを確認すると

Student:{"class":"赤組","number":"1"} : {__typename:'Student',

省略

Student:{"class":"赤組","number":"1"} がキャッシュID(文字列)として、キャッシュが保存されていることがわかります。

自身が持つフィールド(他のtypeのオブジェクト)が持つフィールドを、キャッシュIDとして使いたいパターンの場合

type Partner {
partnerA : User!
partnerB : User!
}

type User {
id: ID!
name: String!
}

PartnerのpartnerAフィールドのidフィールド と
PartnerのpartnerBフィールドのidフィールド をキャッシュIDとして構成したいケース。

この場合は以下のようにInMemoryCacheを設定します。

cache: new InMemoryCache({
    typePolicies: {
      Partner: {
        keyFields: ["partnerA", ["id"], "partnerB", ["id"]],
      },

[]の一個前のフィールドの中に定義されている、[]の中のフィールドをキャッシュIDに使います。
上記の例だと

partnerAフィールドのid と partnerBのidフィールドを、 type PartnerのキャッシュIDとして使用することとなります。

実際に以下のように保存されています。

//Partner:{"partnerA":{"id":"1"},"partnerB":{"id":"3"}}がキー

Partner:{"partnerA":{"id":"1"},"partnerB":{"id":"3"}} :

所感

graphQL apiを作成する際に、

なかなかidがないtypeを見かける機会がありませんでしたが、

dynamoDBを使用したときに、idがtypeに含まれていないケースに遭遇したので、

今回の記事を作成しました。

参考になれば幸いです。

Discussion