GraphQL

名称 = GraphQLGraphQLはAPI向けに作られたクエリ言語およびランタイムである。 ベンダーフリーな GraphQL財団の支援を受け、開発が進められている。

ウェブAPIの開発に、RESTやその他のWebサービスと比較して、効率的で堅牢、かつ柔軟なアプローチを提供する。GraphQLでは、クライアントが必要なデータの構造を定義することができ、サーバーからは定義したのと同じ構造のデータが返される。したがって、必要以上に大きなデータが返されるのを防ぐことができクエリの効率が良い。また、柔軟性と豊かな表現が可能なクエリ言語は複雑さを加えるため、シンプルなAPIには適さない可能性もある。GraphQLは、型システム、クエリ言語、実行セマンティクス、静的な検証、型チェックから構成される。

GraphQLは、データの問い合わせ 、書き換え 、購読  をサポートする。

1. 概要
-----

GraphQLでは、クライアントがクエリ内容を記した//を送信し、GraphQLサービスがクエリを実行し結果を返信する。//document//はDSLである//を用いて記述される。以下の例は明日の天気を取得するクエリの//document//とGraphQLサービスから返されたクエリ結果のJSONである。 // document { tomorrow { weather rainyPercent } } { "tomorrow": { "weather": "cloudy", "rainyPercent": 30 } } リソースをURLパスで表現するREST APIと異なり、GraphQLはリソースを//document//で表現する。GraphQL WebAPIの場合、単一のAPIエンドポイントへこの//document//をPOSTすることでクエリが実行される。

//Document//を受け取ったGraphQLサービスは//Document//中の//  をトップレベルから1つずつ//により値へ解決する。クライアントが受け取りたい値はすべてfieldとして過不足なく//Document//に記載されているので、//resolver//群により全ての//field//を解決すれば過不足ないデータが1回のクエリで得られる。GraphQLサービス処理系はこのfieldからなるグラフ構造を上からresolverを用いて解決する役割を果たす。resolverはサービス実装者により実装される。

構造が事前に決められたリソースへアクセスするREST APIと異なり、GraphQLではその場でdocumentから与えられた構造に対しresolver群を連続適用して解決する。ゆえにREST APIでは定められたリソースしか1度のアクセスでは取得できないが、GraphQLではschema-validな任意のリソースを1度のアクセスで得られる。例えばRESTful APIでは「ある人の友人リスト」APIがあっても「ある人の友人の友人リスト」を得るためには1度友人リストを得たのちにクライアントからもう一度APIを叩く必要がある。一方GraphQLでは「Persion.friends field」resolverさえあれば{personA {friends {friends {name} } } }//Document//をPOSTするだけでresolverが連続適用されて「友人の友人リスト」が1度に得られる。

このようにGraphQLはクライアントからクエリ構造を渡せる柔軟性を持ち、また1度のクエリで必要十分な値のみを得られる効率性を持つ。

GraphQLサービスが受け入れられる型を、IDLである"type system definition language"  で書かれたSchemaで記述する。

GraphQLはあくまでAPI仕様であり、通信方式の実装とは独立している。例えばGraphQL WebAPIを実装する際、//document//をURLクエリ文字列に載せることも可能である。

2. 機能
-----

2.1. //Arguments//
------------------

GraphQLでは//を用いたクエリの制御が可能である。GraphQLオブジェクトの各fieldは0個以上の//arguments//を持てる。GraphQLサービスではクエリをトップレベルのfieldから//によって解決していくが、//arguments//はその時に//resolver//へ渡され//resolver//の振る舞いを制御する。次の例では"都道府県名/name" //argument//と"天気/weather" //argument//を用い、都道府県-街リストから東京/tokyoに含まれる晴れ/sunnyの街を取得する。 // document { prefecture { prefName cities { cityName rainyPercent }}} { "prefecture": { { "prefName": "Tokyo", "cities": [ { "cityName": "Shinjuku", "rainyPercent": 10 },{ "cityName": "Ikebukuro", "rainyPercent": 0 }]}}}

2.2. directives
---------------

GraphQLでは//を用いたクエリの制御が可能である。GraphQLオブジェクトの各fieldは//directive//を持てる。//directives//は処理系に依存したあらゆる処理を指定するアノテーションである。全ての処理系に実装される//directive//の例としてfieldの無視を指定する@includeがある。 { sinjuku { weather } ikebukuro @include { weather rainyPercent }} { "sinjuku": { "weather": "cloudy" }} 全ての//resolver//に@include相当の引数を用意すれば同等の機能を提供できるが、//directives//を用いることで//resolver//に手を加えずかつ//directive//処理系1箇所での実装のみでこの機能を提供できる。

directivesはGraphQLサービス処理系以外にも利用されうる。例えばAWS AmplifyはSchema上の//directivesに基づいたクラウドリソースプロビジョニングコード生成//を実装している。@modelが付与されたfieldは//resolver//が自動で生成されかつDynamoDBにリソースが準備される。これはGraphQLサービス処理系ではなく、Amplify CLIによっておこなわれる。

3. 形式
-----

3.1. //Document//
-----------------

//Document//は1つ以上の//OperationDefinition//からなる。1つのみの場合Nameが省略可能であり、さらに//OperationType//がqueryならこれも省略できる。

3.2. //Field//
--------------

//Field//はNameからなっており、Alias, Arguments, Directivesを利用できる。さらにサブFieldを持つことができる。

4. 処理系
------

4.1. 値解決
--------

値解決はFieldの値を算出するステップである。ResolveFieldValue関数インターフェスに該当し、[オブジェクト型, オブジェクト値, field名, arguments]からfieldの値を生成する