Graphql Tips
RESTとの違い
RESTはHTTPメソッドで操作、URLで操作対象を表している。
GraphQLはオペレーションで操作、query languageで操作対象を表している。
GraphQL(クライアント)
Operation/Fragment名はモジュール名で始める
Operation名は種別(Query, Mutation)で終わる
Fragment名は_<型名>で終わる
eslintで縛る
GraphQL SDL(リゾルバー)
xxxId, xxxID, xxxid の表記揺れ。どうすれば良いか
xxxIDに統一しよう
queryに型をマッピングする
トリビアルリゾルバー
バリデーションを実装できるため、積極的にCustom ScalarやEnumを使う
ex. Datetime
nullを返す予定がない時は積極的にエクスクラメーションマークを使う
nullは悪
複数の型を返したい時はunionにする
nullは悪
無向グラフにしておく(双方向に取得できる)
クライアントからの柔軟性のため
queryはリソースの取得なので名詞で命名。Lキャメル
mutationはリソースに対する操作なので動詞で命名。Lキャメル
削除のmutationの返り値にもidを含める
キャッシュ削除の判断に使うため
型はUキャメル。
変数が二つ以上ある場合は入力型(Input)を使用する。xxxInputという命名
トリプルクオーテーションでコメントを書こう
イントロスペクションに含まれる
追記: # じゃないと識別されなかった
セキュリティ
サーバーにリクエストタイムアウトを設定する
データ制限
ページングの最大値を設定する
クエリのネストの深さを制限する
クエリ複雑度
実行時間、エラー監視
追加仕様
Relayで定義されている追加の仕様
Global Object ID
正直使いどころがわかっていない、、
全データを共通のIDで一意にする
code:graphql
type Query {
node(id: ID!): Node
}
interface Node {
id: ID!
}
type User implements Node {
id: ID!
name: String
}
Cursor Connection
ページングのための実装
offsetベースの実装との違いはより厳密にクエリできるか
cursorベースの場合は実レコードのIDからの位置を指定している
デメリット: ページネーションのskipができない
offsetベースはクエリ時点での先頭からの位置を指定している
リストを返す場所でConnection(pageInfoとedges)サフィックスを持つ型を返す
ex. type UserConnection { ... }
first: Int! と after: Stringを引数に追加
Edge型(cursor, node)とPageInfo型を持つ
cursorは基本的にnodeのid
code:graphql
type Query {
repositories(
# 次方向ページングの時に使う
first: Int # 取得数
after: String # 開始位置
# 前方向ページングの時に使う。
last: Int
before: String
): RepositoryConnection
}
type RepositoryConnection {
pageInfo: PageInfo
totalCount: Int!
}
type PageInfo {
hasPreviousPage: Boolean!
startCursor: String # 取得した最初のnodeのcursor
hasNextPage: Boolean!
endCursor: String # 取得した最後のnodeのcursor
}
type RepositoryEdge {
cursor: String! # なくても良い
node: Repository
}
type Repository {
id: ID!
name: String!
}
参考