GraphQLでMutation


本記事では「Spring BootでGraphQLを実装する」で使ったサンプルアプリを例に記述します。

Mutationのスキーマ定義

まずMutationの命名はアプリケーションと紐づく動詞が望ましいです。今回は、id、name、pageCountの3つを引数に取り戻り値はBook型のスキーマを定義してみます。
※この後の説明の都合上、nameフィールドは必須、それ以外は非必須となる引数としています。
※「!」の詳細は「GraphQLのスキーマと型定義のエクスクラメーションマークの意味」を参照ください。

schema.graphqls
type Mutation {
    registerBook (
        id: ID
        name: String!
        pageCount: Int
    ): Book
}

サーバーサイド

サーバーサイドの実装は以下の通りです。GraphQLMutationResolverをimplementsする必要があります(Javaで実装しているためこのようにしています、他の言語では違った形になるかと思います)。また、スキーマ定義に記述した通り、id、name、pageCountの3つを引数に取り戻り値はBook型のリゾルバであるregisterBookを定義します(コメントにもあるように中身はダミー実装です)
※リゾルバについては「GraphQLのリゾルバ(Resolver)とは」を参照ください。

BookResolver.java
@Component
public class BookResolver implements GraphQLQueryResolver, GraphQLMutationResolver {

    public Book bookById(String bookId) {
        // 実際は何らかのデータストアからデータを読み込み返却するケースがほとんどだが、ここではダミー値を返却
        Book book = new Book();
        book.setId(bookId);
        book.setName("bookName");
        book.setPageCount(900);
        Author author = new Author();
        author.setId("0001");
        author.setFirstName("fName");
        author.setLastName("lName");
        book.setAuthor(author);
        return book;
    }

    public Book registerBook(String id, String name, int pageCount) {
        // 実際はここでデータ登録処理を行う

        // GraphQLのスキーマ定義に則りBookを返却。一般的には登録後のデータを返却する。
        Book book = new Book();
        book.setId(id);
        book.setName(name);
        book.setPageCount(pageCount);

        return book;
    }
}

Mutationの実行

実際にMutationを投げてみます。全ての引数を設定して以下のように投げることができます。スキーマ定義上Book型が返ってくるため、ここではBook型の中のidとnameをレスポンスとしてもらうようなクエリにしています。

mutation {
  registerBook(id: "1", name:"bookName", pageCount:100) {
    id
    name
  }
}

レスポンスは以下のようになります。

{
  "data": {
    "registerBook": {
      "id": "1",
      "name": "bookName"
    }
  }
}

registerBookのname引数は必須なため、以下のようなクエリは構文エラーとなります。

mutation {
  registerBook(id:"1", pageCount:100) {
    id
    name
  }
}

逆に、name以外の引数は非必須なため、以下のようなクエリは実行可能です(必須な引数のみの指定)。

mutation {
  registerBook(name:"bookName") {
    id
    name
  }
}

1回のMutationで複数のデータ登録

複数のデータを登録するためにmutationにもう1つフィールドを追加します。ここではregisterAuthorを追加します。

schema.graphqls
type Mutation {
    registerBook (
        id: ID
        name: String!
        pageCount: Int
    ): Book

    registerAuthor (
        id: ID
        firstName: String
        lastName: String
    ): Author
}

サーバーサイドも以下のようにregisterAuthorを追加します。

BookResolver.java
@Component
public class BookResolver implements GraphQLQueryResolver, GraphQLMutationResolver {

    public Book bookById(String bookId) {
        // 実際は何らかのデータストアからデータを読み込み返却するケースがほとんどだが、ここではダミー値を返却
        Book book = new Book();
        book.setId(bookId);
        book.setName("bookName");
        book.setPageCount(900);
        Author author = new Author();
        author.setId("0001");
        author.setFirstName("fName");
        author.setLastName("lName");
        book.setAuthor(author);
        return book;
    }

    public Book registerBook(String id, String name, int pageCount) {
        // 実際はここでデータ登録処理を行う

        // GraphQLのスキーマ定義に則りBookを返却。一般的には登録後のデータを返却する。
        Book book = new Book();
        book.setId(id);
        book.setName(name);
        book.setPageCount(pageCount);

        return book;
    }

    public Author registerAuthor(String id, String firstName, String lastName) {
        // 実際はここでデータ登録処理を行う

        // GraphQLのスキーマ定義に則りAuthorを返却。一般的には登録後のデータを返却する。
        Author author = new Author();
        author.setId(id);
        author.setFirstName(firstName);
        author.setLastName(lastName);

        return author;
    }
}

クエリは以下の通りです。

mutation {
  registerBook(id:"1", name:"bookName", pageCount:100) {
    id
    name
    pageCount
  }
  registerAuthor(id:"1", firstName:"fName", lastName: "lName") {
    id
    firstName
    lastName
  }
}

クエリ変数を使ってMutationを実行

「クエリ変数」というものを使ってMutationで登録する値を動的に変えることも可能です。クエリは以下のようになります。

mutation createBook($id:ID $name:String! $pageCount:Int) {
  registerBook(id:$id, name:$name, pageCount: $pageCount) {
    id
    name
    pageCount
  }
  registerAuthor(id:$id, firstName:"fName", lastName: "lName") {
    id
    firstName
    lastName
  }
}

クエリ変数を受け取るために構文上mutationの後に任意のmutation名が必要です(上記ではcreateBookとしています)。クエリ変数は頭に「$」を付けて任意の変数名となります。

GraphiQL、GraphQL Playgroundにはクエリ変数ウィンドウがあるので、そのウィンドウにて変数にセットする値をJSON形式で設定して実行します。JSONのキー名がクエリ変数名になります。

以上です。