【備忘録】GraphQLで取り扱いづらいデータ構造について

1322
NO IMAGE

GraphQLを調査

現在関わっているプロジェクトにGraphQLを適用して、一般的なAPIの口を用意できないか?という話があがり、GraphQLが適用できそうか調査した。
結論としては、あまり導入するメリットが無さそうだとなったが、メモを残しておく。

GraphQLと対象プロジェクトのデータでのギャップ

既存のプロジェクトのデータをGraphQLのスキーマ定義で表現できるのか?について調べた結果、いろいろとギャップが出た

Genericsに該当するものが無い

型パラメータ部分をinterfaceかunionかで無理やり回避くらいしか無いか?

Mapがうまく取り扱えない

  • Key-Valueのペアのリストで表現
    type HogeKeyValue {
    key: HogeType
    value: HogeValue
    }
    type Fuga {
    name: String
    hoge: [HogeKeyValue]
    }

    無駄に一段ネストされる

  • CustomScalarTypeで回避
    • Mapの時点でスカラーとなってしまうため、この先のデータハンドリングができなくなる

Enumがとても単純にしか定義できない

対象プロジェクトでは、インターフェース⇒Enumの実体が複数実装という形でデータを持てるが、これが表現できない
GraphQLではenumはunionで表せない
type定義でラップするなどしないといけない

インターフェースが定義できるが、実際の型にもフィールド定義が必要で手間

interface NamedEntity {
  name: String
}
type Person implements NamedEntity {
  name: String
  age: Int
}
type Company implements NamedEntity {
  name: String
  employeeCount: Int
}

SELECT * のように全フィールド指定ができない

リクエストで欲しい形そのままで指定が必要

インターフェースを定義できるが、取得時には、実体の型とフィールドを指定しないと駄目

#実体の型ごとに、取得フィールドを指定しないといけない
... on Cylinder {
  diameter
  height
}
... on Prism {
  height
  width
  depth
}

リクエストする際は、末端のスカラーのフィールドを指定しないと取ってこれない

オブジェクトで止めたりできない

再帰構造をうまくクエリで書けない

再帰構造のスキーマは普通に定義できるが、クエリでfragmentを再帰的に書いたりしてもエラーになる
ただ、クエリをネストして書くことはできる

 #こういうのはエラーになる
 fragment HogeFields on Hoge {
   name
   children {
     ...HogeFields
   }
 }
 # ネストして書くことはできる
 query fetchRecursive() {
   hoge {
     name
     children {
       name
       children {
         name
         children {
           name
         }
       }
     }
   }
 }

まとめ

フィールドを指定して最低限のレスポンスにできること、スキーマ定義がちゃんとしていれば、自由度高くユースケースにあわせて、データをリクエストできそうなことはメリットで良く述べられているが、MapとリストとGenericsがうまいこと表現しづらいため、既存プロジェクトのデータは取り扱いづらいことがわかった。