ApolloClientのベストプラクティスがあったので自分でまとめてみた

## 全てのオペレーションに名前をつける

- 利点
  - 意図したオペレーションをフロントとバックエンドで共有ができる
  - 予期せぬエラーの回避
  - デバックでフロントとバックエンドのどちらに原因があるかを特定するのに役だつ

```graphql
# 推奨 ✅
query GetBooks {
  books {
    title
  }
}

# 非推奨 ❌
query {
  books {
    title
  }
}
```

## 変数を利用して引数を提供する
- 実行するuseQueryからvariavlesオプションを利用することで変数を提供することが可能

```javascript
// 推奨 ✅
query GetDog($dogId: ID!) {
  dog(id: $dogId) {
    name
    breed
  }
}

// 非推奨 ❌
query GetDog {
  dog(id: "5") {
    name
    breed
  }
}

function Dog({ id }) {
  const { loading, error, data } = useQuery(GET_DOG, {
    variables: {
      dogId: id
    },
  });
  // ...render component...
}
```
### 注意

::: note alert
ハードコードされた引数が引き起こすデメリット(変数に比べて他の欠点)
・キャッシュの効果を下げる
・プライバシーが表示されるためセキュリティの低下につながる
:::

:::note info
ハードコーディングとは?
分けておいた方が良い処理や値をコードに直書きしてしまうこと
:::

https://wa3.i-3-i.info/word12866.html

## 必要な場所で、必要なデータのみ取得する
REST APIを上回るメリットがここであるからこそ、無駄にデータを取得するクエリ(フィールド)を書かずに正確にクエリを書きましょう。

```graphql
# Not recommended ❌
query GetGlobalStatus {
  stores {
    id
    name
    address {
      street
      city
    }
    employees {
      id
    }
    manager {
      id
    }
  }
  products {
    id
    name
    price {
      amount
      currency
    }
  }
  employees {
    id
    role
    name {
      firstName
      lastName
    }
    store {
      id
    }
  }
  offers {
    id
    products {
      id
    }
    discount {
      discountType
      amount
    }
  }
}
```

## フラグメントで再利用性のあるフィールドを作成

再利用性はカプセル化ともいう

### 良い例
viewerとuserのフィールドが同じクエリ

```graphql
query QueryTwoUsers {
# viewerとuserのフィールドが同じ
  viewer {
    login       # ログインID
    name        # ユーザー名
    url         # ユーザーの GitHub ホームページ
  }

  user(login: "ログイン中のusrID") {
    login
    name
    url
  }
}
```

そこでフラグメントを利用する

```graphql
query QueryTwoUsers {
  viewer {
  # 「...」は反復可能オブジェクトであるuserFragmentを展開
    ...userFragment
  }

  user(login: "ログインID") {
  # 「...」は反復可能オブジェクトであるuserFragmentを展開
    ...userFragment
  }
}
#フラグメントを定義
fragment userFragment on User {
  login      
  name       
  url      
}
# フラグメントが長くなったらこのように１列にもできるみたい
fragment userFragment on User {
  login name url
}
```
https://maku.blog/p/wiv7it5/

### 注意
::: note alert
可読性を下げてしまう可能性がある
:::

- フラグメントを使いすぎる

```graphql
query GetAttendees($eventId: ID!) {
  attendees(id: $eventId) {
    id
    rsvp
    ...NameParts
    profile {
      ...VisibilitySettings
      events {
        ...EventSummary
      }
      avatar {
        ...ImageDetails
      }
    }
  }
}
```
- 非ロジカルなフラグメント

```graphql
# 推奨 ✅
fragment NameParts on Person {
  title
  firstName
  middleName
  lastName
}

# 非推奨 ❌
fragment SharedFields on Country {
  population
  neighboringCountries {
    capital
    rivers {
      name
    }
  }
}
```

## グローバルデータとローカルデータを混合させない

### よくない例
```graphql
query GetAllElements {
  # グローバルで活用するデータ
  elements {
    atomicNumber
    name
    symbol
  }
  # ローカルで活用するデータ
　myDocuments {
    id
    title
    url
    updatedAt
  }
}
```

### よい例

```graphql
query GetAllElements {
  elements {
    atomicNumber
    name
    symbol
  }
}
```

```graphql
query GetMyDocuments {
  myDocuments {
    id
    title
    url
    updatedAt
  }
}
```

****

参考

https://www.apollographql.com/docs/react/data/operation-best-practices/