GraphQL

GraphQL（グラフQL）はAPI向けに作られたクエリ言語およびランタイムである。 ベンダーフリーな GraphQL財団の支援を受け、開発が進められている。 ウェブAPIの開発に、RESTやその他のWebサービスと比較して、効率的で堅牢、かつ柔軟なアプローチを提供する。GraphQLでは、クライアントが必要なデータの構造を定義することができ、サーバーからは定義したのと同じ構造のデータが返される。したがって、必要以上に大きなデータが返されるのを防ぐことができクエリの効率が良い。また、柔軟性と豊かな表現が可能なクエリ言語は複雑さを加えるため、シンプルなAPIには適さない可能性もある。GraphQLは、型システム、クエリ言語、実行セマンティクス、静的な検証、型チェックから構成される。 GraphQLは、データの問い合わせ (query)、書き換え (mutation)、購読 (subscription) をサポートする。 GraphQLでは、クライアントがクエリ内容を記したdocumentを送信し、GraphQLサービスがクエリを実行し結果を返信する。documentはDSLであるGraphQL query languageを用いて記述される。以下の例は明日の天気を取得するクエリのdocumentとGraphQLサービスから返されたクエリ結果のJSONである。 // document { tomorrow { weather rainyPercent } } { "tomorrow": { "weather": "cloudy", "rainyPercent": 30 } } リソースをURLパスで表現するRESTful APIと異なり、GraphQLはリソースをdocumentで表現する。GraphQL WebAPIの場合、単一のAPIエンドポイントへこのdocumentをPOSTする（例:https://API.internal./graphqlエンドポイントへdocumentをBodyとしてPOSTする）ことでクエリが実行される（参考: アプリケーションプログラミングインタフェース#様式 ）。 Documentを受け取ったGraphQLサービスはDocument中のfield (例: tomorrow) をトップレベルから1つずつresolverにより値へ解決する。クライアントが受け取りたい値はすべてfieldとして過不足なくDocumentに記載されているので、resolver群により全てのfieldを解決すれば過不足ないデータが1回のクエリで得られる。GraphQLサービス処理系はこのfieldからなるグラフ構造を上からresolverを用いて解決する役割を果たす。resolverはサービス実装者により実装される。 構造が事前に決められたリソースへアクセスするRESTful APIと異なり、GraphQLではその場でdocumentから与えられた構造に対しresolver群を連続適用して解決する。ゆえにRESTful 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 definition languageとも) で書かれたSchemaで記述する。 GraphQLはあくまでAPI仕様であり、通信方式の実装とは独立している。例えばGraphQL WebAPIを実装する際、documentをURLクエリ文字列に載せることも可能である（例:GET https://API.internal./graphql?query={tomorrow{weather}}）。 GraphQLではargumentを用いたクエリの制御が可能である。GraphQLオブジェクトの各field（例: tomorrow）は0個以上のargumentsを持てる。GraphQLサービスではクエリをトップレベルのfieldからresolverによって解決していくが、argumentsはその時にresolverへ渡されresolverの振る舞いを制御する。次の例では"都道府県名/name" argumentと"天気/weather" argumentを用い、都道府県-街リストから東京/tokyoに含まれる晴れ/sunnyの街を取得する。 // document { prefecture(name: "Tokyo") { prefName cities(weather: "sunny") { cityName rainyPercent }}} { "prefecture": { { "prefName": "Tokyo", "cities": [ { "cityName": "Shinjuku", "rainyPercent": 10 },{ "cityName": "Ikebukuro", "rainyPercent": 0 }]}}} GraphQLではdirectivesを用いたクエリの制御が可能である。GraphQLオブジェクトの各field（例: tomorrow）はdirectiveを持てる。directivesは処理系に依存したあらゆる処理を指定するアノテーションである。全ての処理系に実装されるdirectiveの例としてfieldの無視を指定する@include(if: Boolean)がある。 { sinjuku { weather } ikebukuro @include(if: false) { weather rainyPercent }} { "sinjuku": { "weather": "cloudy" }} 全てのresolverに@include相当の引数を用意すれば同等の機能を提供できるが、directivesを用いることでresolverに手を加えずかつdirective処理系1箇所での実装のみでこの機能を提供できる。 directivesはGraphQLサービス処理系以外にも利用されうる。例えばAWS AmplifyはSchema上のdirectivesに基づいたクラウドリソースプロビジョニングコード生成（"GraphQL Transform"）を実装している。@modelが付与されたfieldはresolverが自動で生成されかつDynamoDBにリソースが準備される。これはGraphQLサービス処理系ではなく、Amplify CLIによっておこなわれる。 Documentは1つ以上のOperationDefinitionからなる。1つのみの場合Nameが省略可能であり、さらにOperationTypeがqueryならこれも省略できる。 // document OpType Name [VarDef][Directives] { ... } OpType Name [VarDef][Directives] { ... } // e.g. query ExampleQuery1 { resource } query ExampleQuery2 ($var: S) @skip(if: false) { time } FieldはNameからなっており、Alias, Arguments, Directivesを利用できる。さらにサブFieldを持つことができる。 // document { [Alias] Name [Arguments][Directives] [SelectionSet] } // e.g.1 - simple { resource } // e.g.2 - full { time: resource (arg1: "arg") @skip(if:false) { subResource } } 値解決（Value Resolution）はFieldの値を算出するステップである。ResolveFieldValue関数インターフェスに該当し、[オブジェクト型, オブジェクト値, field名, arguments]からfieldの値を生成する（例: Person型, Obamaオブジェクト, job fieldName, no argument => presidentfield value)。擬似JavaScriptコードで以下になる。 function ResolveFieldValue(objectType, objectValue, fieldName, argumentValues){ const resolver = getExternalResolver(ojectType, fieldName); return resolver(objectValue, argumentValues); } GraphQLは、2012年にFacebookの内部で開発され、2015年に公開された。2018年11月7日、GraphQLプロジェクトは、Facebookから非営利のLinux Foundationがホストする新たに設立されたGraphQL Foundationに移譲された。2012年以来、GraphQLの利用数は、GraphQLの作者のLee Byronが想定したとおりのスケジュールに正確に従って増加している 。Byronの目標は、GraphQLをWebプラットフォーム全体で利用されるようにすることである。 2018年2月9日、GraphQL Schema Definition Language（SDL）が仕様の一部となった。 GraphQLクライアントは適切なdocumentをGraphQL APIエンドポイントへPOSTするだけでクエリを実行できるため、ライブラリを採用せずとも容易にクエリを実行できる。 より高度な機能を有するGraphQLクライアント実装としては、Apollo ClientとRelayがある。 GraphQLサーバーは複数の言語で利用可能であり、Haskell、JavaScript、Perl、Python、Ruby、Java、C#、Scala、Go、Elixir、Erlang、PHP、R、Clojureで書かれたものがある。 GitHubは第4世代のAPIとしてGraphQL API「GitHub GraphQL API v4」を提供している。 GitHubはその選定理由として「more flexibility for our integrators（我々のインテグレータに対する更なる柔軟性）」を挙げている。GitHubではIssueをプロジェクト管理アプリに組み込むシステムインテグレータ、CI/CDパイプラインを管理するエンジニアやライブラリ作者、レポジトリ統計を取り出す個人など、多様なAPI利用者を抱えている。その多様な要求から、全ての利用者に必要かつ十分な（オーバーフェッチもアンダーフェッチもしない）APIを提供することは困難である（無数のREST APIエンドポイント・サーバー実装は管理しきれない）。結果として一部の利用者にとっては柔軟性が足りなく感じられていた。GitHubはレスポンス種に限りがあるREST APIから利用者側がレスポンス（クエリ構造）を指定するGraphQLにAPIを変更し、上記の問題を解決した。 Query by Example OpenAPI Specification ^ “GraphQL June 2018 Release Notes”. 26 March 2019閲覧。 ^ GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. https://graphql.org/ ^ GraphQL foundation. https://graphql.org/foundation/ ^ “GraphQL vs REST: Overview” (英語). Phil Sturgeon. (2017年1月24日). https://phil.tech/api/2017/01/24/graphql-vs-rest-overview/ 2018年11月25日閲覧。  ^ “Why use GraphQL, good and bad reasons” (英語). Honest Engineering. (2018年8月4日). https://honest.engineering/posts/why-use-graphql-good-and-bad-reasons 2018年11月26日閲覧。  ^ “GraphQL Fundamentals”. Howto GraphQL. 4 July 2018閲覧。 ^ “GraphQL”. facebook.github.io. Facebook. 4 July 2018閲覧。 ^ Clients use the GraphQL query language to make requests to a GraphQL service. We refer to these request sources as documents. GraphQL specification ^ When receiving an HTTP GET request, the GraphQL query should be specified in the "query" query string. GraphQL ^ Every field on a GraphQL object type can have zero or more arguments GraphQL specification ^ Each field on each type is backed by a function called the resolver which is provided by the GraphQL server developer. When a field is executed, the corresponding resolver is called to produce the next value. GraphQL ^ A directive can be attached to a field or fragment inclusion, and can affect execution of the query in any way the server desires. GraphQL ^ Directives provide a way to describe alternate runtime execution and type validation behavior in a GraphQL document GraphQL Specification ^ Because the Todo type was decorated with an @model directive of the GraphQL Transform library, the CLI created the additional schema and resolvers for queries, mutations, and subscriptions as well as a DynamoDB table to hold the Todos. Amplify Libraries ^ This is exposed via ResolveFieldValue, which produces a value for a given field on a type for a real value. 6.4.2 Value Resolution ^ “GraphQL: A data query language”. 2019年10月19日閲覧。 ^ “Facebook’s GraphQL gets its own open-source foundation” (英語). TechCrunch. https://techcrunch.com/2018/11/06/facebooks-graphql-gets-its-own-open-source-foundation/ 2018年11月7日閲覧。  ^ “The Linux Foundation Announces Intent to Form New Foundation to Support GraphQL - The Linux Foundation” (英語). The Linux Foundation. (2018年11月6日). https://www.linuxfoundation.org/press-release/2018/11/intent_to_form_graphql/ 2018年11月7日閲覧。  ^ Anthony. “Is GraphQL Moving Toward Ubiquity?”. NordicAPIs. 2019年10月19日閲覧。 ^ “[RFC GraphQL Schema Definition Language (SDL) by leebyron · Pull Request #90 · graphql/graphql-spec]” (英語). GitHub. 2019年10月19日閲覧。 ^ But you don't need a complex client to call a GraphQL server. With express-graphql, you can just send an HTTP POST request to the endpoint you mounted your GraphQL server on, passing the GraphQL query as the query field in a JSON payload. graphql.org ^ “Introduction”. Apollo GraphQL Docs. 2019年10月19日閲覧。 ^ “Relay · A JavaScript framework for building data-driven React applications” (英語). relay.dev. 2019年10月19日閲覧。 ^ A reference implementation of GraphQL for JavaScript: graphql/graphql-js, GraphQL, (2019-10-19), https://github.com/graphql/graphql-js 2019年10月19日閲覧。  ^ “GraphQL - Perl implementation of GraphQL - metacpan.org”. metacpan.org. 2019年10月19日閲覧。 ^ “Graphene”. graphene-python.org. 2017年6月18日閲覧。 ^ “Absinthe: The GraphQL toolkit for Elixir”. 19 July 2018閲覧。 ^ GitHub chose GraphQL for our API v4 GitHub Developer ^ because it offers significantly more flexibility for our integrators. GitHub Developer ^ Despite all the information we provided, we heard from integrators that our REST API also wasn’t very flexible. GitHub blog 公式ウェブサイト