All Articles

GraphQL 周り Schema編

命名規則

  • Query

    • getXXX
    • getXXXs [複数形]
  • Mutation

    • 動詞 + 名詞
    • addXXX, createXXX。Github は db 操作のような insertXXX は使っていない。あくまでビジネス処理としての言葉を使っている。delete と remove は両方使っている。
    • 引数
    • [Mutation]Input. ex.) AddProjectInput
    • 返り値
    • [Mutation]Payload. ex.) AddProjectPayload

Connection

GitHubのGraphQL APIでは、Connectionを使用して、リレーションシップやページネーションを表現します。Connectionは、次のような要素で構成されています。

  • Edges: コレクション内の個々の要素を表すオブジェクト。通常、データの実際のレコードまたはエンティティです。
  • Node: Edge内のデータを表現するためのフィールド。これは通常、エッジに関連する実際のデータのプロパティやフィールドです。
  • Cursor: Edgeを識別するための一意の識別子。通常はデータの一意の識別子やキーです。
  • Page Info: クエリのページネーション情報を提供するためのメタ情報。通常、クエリの結果セットに関する追加の情報(例:次のページがあるかどうか、カーソルの位置など)を提供します。

GitHubのGraphQL APIでは、Connectionを定義する際にこれらの要素が使用されます。たとえば、GitHubのリポジトリやイシューをクエリする場合、Connectionを使用して結果がページネーションされ、エッジごとに個々のデータが提供されます。

type Query {
  repositories(first: Int, after: String): RepositoryConnection!
}

type RepositoryConnection {
  edges: [RepositoryEdge!]!
  pageInfo: PageInfo!
}

type RepositoryEdge {
  cursor: String!
  node: Repository!
}

type Repository {
  id: ID!
  name: String!
  description: String
}

Tips

  • Query には極力 Object を渡さない

    • Github ではやっていない。

このへんが辛い

  1. フロント側的には input でまとめなくても variables でまとまる
  2. 引数を明示的に指定するのは 2-3 がほとんどであまり多くならない
  3. デフォルト値の指定が活用できずつらい

Node

ID を使った Get や List は Interface を実装した node(id (ID!)), nodes(ids ([ID!]!)) のような形で定義しておくと個々の Object ごとに XXXByID のようなメソッドを生やさなくて済む。Github ではこの手段をとっている。

type Query {
   node(id: ID!): Node
}
interface Node {
   id: ID!
}
type User implements Node {
   id: ID!
   name: String
}

クライアントは fragment を使って指定する

query {
  node(id: "User:1") {
    id
    ... on User {
      name
      email
    }
  }
}

Todo: この辺サーバの実装はどうなるんだろうか。switch して分けるしかない。。?type で判定してやるぽい。

directive

GraphQLのディレクティブは、クエリやスキーマ定義に対してメタデータや動作を追加するための機能です。ディレクティブは@で始まり、フィールドやフラグメント、変数定義などに適用することができます。
ディレクティブはGraphQLスキーマの柔軟性と拡張性を高めるために使用されます。

directive @directiveName(
  argumentName: Type,
  ...
) on
  | SCHEMA
  | SCALAR
  ...

ここで、各要素は以下の意味を持ちます。

  • @directiveName: ディレクティブの名前
  • argumentName: Type: ディレクティブが受け取る引数の定義
  • on: ディレクティブが適用可能な場所を指定する

具体的な例

directive @hide(if: Boolean!) on FIELD_DEFINITION

type User {
  id: ID!
  name: String!
  email: String! @hide(if: true)
  age: Int!
}

利用方法

query($hideEmail: Boolean!) {
  user(id: "1") {
    id
    name
    email @hide(if: $hideEmail)
    age
  }
}