1概要
GraphQL は、直観的で柔軟な構文に基づいてクライアントアプリケーションを構築することを目的としてFacebookによって作成された、それらのデータ要件および相互作用を記述するためのクエリー言語です。
従来のREST呼び出しの主な課題の1つは、クライアントがカスタマイズされた(制限された、または拡張された)データセットを要求できないことです。ほとんどの場合、クライアントがサーバーから情報を要求すると、すべてのフィールドを取得するか、フィールドをまったく取得しません。
もう1つの問題は、複数のエンドポイントを機能させて維持することです。プラットフォームが成長するにつれて、その結果、数は増えます。したがって、クライアントは異なるエンドポイントからデータを要求する必要があることがよくあります。
GraphQLサーバーを構築するとき、すべてのデータのフェッチと変換のために1つのURLを持つことだけが必要です。したがって、クライアントは、必要なものを記述したクエリ文字列をサーバーに送信することによって、一連のデータを要求できます。
2基本的なGraphQLの命名法
GraphQLの基本用語を見てみましょう。
-
Query: はGraphQLサーバーに要求される読み取り専用操作です。
-
Mutation: はGraphQLサーバーに要求される読み書き操作です。
-
リゾルバー: GraphQLでは、 Resolver が
責任を負うバックエンドで実行されている操作とコード 要求を処理します。 RESTFulのMVCバックエンドに似ています 応用 Type:** Type は応答データの形を定義する
GraphQLサーバーから返されます。 その他のタイプ Input:** は Typeのように ですが、入力データの形状を定義します。
GraphQLサーバーに送信された スカラー:** は、 String 、 Int 、 Boolean などのプリミティブ Type です。
フロート など インタフェース:** インタフェースはフィールドの名前とその名前を保存します。
そのため、GraphQLオブジェクトはそれを継承することができます。 特定の分野 スキーマ:** GraphQLでは、スキーマはクエリと変換を管理します。
GraphQLサーバーで実行できるものを定義する
2.1. スキーマロード
GraphQLサーバーにスキーマをロードする方法は2つあります。
-
GraphQLのInterface Definition Language(IDL)を使用して
-
サポートされているプログラミング言語の1つを使用して
IDLを使った例を見てみましょう。
type User {
firstName: String
}
では、Javaコードを使用したスキーマ定義の例を次に示します。
GraphQLObjectType userType = newObject()
.name("User")
.field(newFieldDefinition()
.name("firstName")
.type(GraphQLString))
.build();
3インターフェース定義言語
GraphQLスキーマを指定する最も簡潔な方法は、インタフェース定義言語(IDL)またはスキーマ定義言語(SDL)です。構文は明確に定義されており、公式のGraphQL仕様で採用される予定です。
たとえば、User/Emails用のGraphQLスキーマを次のように指定します。
schema {
query: QueryType
}
enum Gender {
MALE
FEMALE
}
type User {
id: String!
firstName: String!
lastName: String!
createdAt: DateTime!
age: Int! @default(value: 0)
gender:[Gender]!
emails:[Email!]! @relation(name: "Emails")
}
type Email {
id: String!
email: String!
default: Int! @default(value: 0)
user: User @relation(name: "Emails")
}
4 GraphQL-java
GraphQL-javaは仕様とhttps://github.com/graphql/graphql-js[Javascriptリファレンス実装]に基づいた実装です。]正しく実行するには少なくともJava 8が必要です。
4.1. GraphQL-javaアノテーション
GraphQLはまた、伝統的なIDLアプローチの使用によって作成されたすべての定型コードを使用せずにhttps://github.com/graphql-java/graphql-java-annotations[Java annotations]を使用してそのスキーマ定義を生成することを可能にします。
4.2. 依存関係
例を作成するために、まずhttps://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22com.graphql-java%22%20AND%20aに依存している必要な依存関係のインポートを始めましょう%3A%22graphql-java-annotations%22[Graphql-java-annotations]モジュール:
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java-annotations</artifactId>
<version>3.0.3</version>
</dependency>
アプリケーションの設定を簡単にするためにHTTPライブラリも実装しています。 Ratpack (ただし、 Vert.x、Spark、Dropwizard、Spring Bootなどでも実装できます。
Ratpackの依存関係もインポートしましょう。
<dependency>
<groupId>io.ratpack</groupId>
<artifactId>ratpack-core</artifactId>
<version>1.4.6</version>
</dependency>
4.3. 実装
例を作成しましょう。ユーザーに「CRUDL」(作成、取得、更新、削除、一覧表示)を提供する簡単なAPIです。まず、 User POJOを作成しましょう。
@GraphQLName("user")
public class User {
@GraphQLField
private Long id;
@GraphQLField
private String name;
@GraphQLField
private String email;
//getters, setters, constructors, and helper methods omitted
}
このPOJOでは、 @ GraphQLName(“ user”) アノテーションを見ることができます。これは、このクラスがGraphQLによって__@GraphQLField.アノテーションが付けられた各フィールドと共にマップされていることを示しています。
次に、 UserHandler クラスを作成します。このクラスは、選択したHTTPコネクタライブラリ(この場合はRatpack)からハンドラメソッドを継承します。このハンドラメソッドは、GraphQLの Resolver 機能を管理および呼び出します。したがって、リクエスト(JSONペイロード)を適切なクエリーまたは変換操作にリダイレクトします。
@Override
public void handle(Context context) throws Exception {
context.parse(Map.class)
.then(payload -> {
Map<String, Object> parameters = (Map<String, Object>)
payload.get("parameters");
ExecutionResult executionResult = graphql
.execute(payload.get(SchemaUtils.QUERY)
.toString(), null, this, parameters);
Map<String, Object> result = new LinkedHashMap<>();
if (executionResult.getErrors().isEmpty()) {
result.put(SchemaUtils.DATA, executionResult.getData());
} else {
result.put(SchemaUtils.ERRORS, executionResult.getErrors());
LOGGER.warning("Errors: " + executionResult.getErrors());
}
context.render(json(result));
});
}
さて、クエリ操作をサポートするクラス、つまり__UserQuery。サーバーからクライアントへデータを取得するすべてのメソッドは、このクラスによって管理されます。
@GraphQLName("query")
public class UserQuery {
@GraphQLField
public static User retrieveUser(
DataFetchingEnvironment env,
@NotNull @GraphQLName("id") String id) {
//return user
}
@GraphQLField
public static List<User> listUsers(DataFetchingEnvironment env) {
//return list of users
}
}
UserQueryと同様に、 UserMutation、__を作成します。これは、サーバー側に格納された特定のデータを変更することを意図したすべての操作を管理します。
@GraphQLName("mutation")
public class UserMutation {
@GraphQLField
public static User createUser(
DataFetchingEnvironment env,
@NotNull @GraphQLName("name") String name,
@NotNull @GraphQLName("email") String email) {
//create user information
}
}
UserQuery クラスと UserMutation クラスの両方のアノテーションに注目する価値があります。
GraphQL-javaサーバーがクエリおよび変換操作を実行できるので、次のJSONペイロードを使用してサーバーに対するクライアントの要求をテストできます。
-
CREATE操作の場合:
{
"query": "mutation($name: String! $email: String!){
createUser (name: $name email: $email) { id name email age } }",
"parameters": {
"name": "John",
"email": "[email protected]"
}
}
この操作に対するサーバからの応答として:
{
"data": {
"createUser": {
"id": 1,
"name": "John",
"email": "[email protected]"
}
}
}
-
RETRIEVE操作の場合:
{
"query": "query($id: String!){ retrieveUser (id: $id) {name email} }",
"parameters": {
"id": 1
}
}
この操作に対するサーバからの応答として:
{
"data": {
"retrieveUser": {
"name": "John",
"email": "[email protected]"
}
}
}
GraphQLは、クライアントがレスポンスをカスタマイズできる機能を提供します。そのため、例として使用した最後のRETRIEVE操作では、名前と電子メールアドレスを返す代わりに、たとえば電子メールだけを返すことができます。
{
"query": "query($id: String!){ retrieveUser (id: $id) {email} }",
"parameters": {
"id": 1
}
}
そのため、GraphQLサーバーから返される情報は、要求されたデータのみを返します。
{
"data": {
"retrieveUser": {
"email": "[email protected]"
}
}
}
5結論
GraphQLは、REST APIの代替アプローチとして、クライアント/サーバー間の複雑さを最小限に抑えるための簡単で非常に魅力的な方法です。
いつものように、例は私達のhttps://github.com/eugenp/tutorials/tree/master/graphql/graphql-java[GitHub repository]で利用可能です。