GraphQLでMutation

本記事では「[Spring BootでGraphQLを実装する](https://qiita.com/NagaokaKenichi/items/2770b151e86fb65ea11d)」で使ったサンプルアプリを例に記述します。

## Mutationのスキーマ定義
まずMutationの命名はアプリケーションと紐づく動詞が望ましいです。今回は、id、name、pageCountの3つを引数に取り戻り値はBook型のスキーマを定義してみます。
※この後の説明の都合上、nameフィールドは必須、それ以外は非必須となる引数としています。
※「!」の詳細は「[GraphQLのスキーマと型定義のエクスクラメーションマークの意味](https://qiita.com/NagaokaKenichi/items/d341dc092012e05d6606#%E3%82%A8%E3%82%AF%E3%82%B9%E3%82%AF%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%9E%E3%83%BC%E3%82%AF%E3%83%9E%E3%83%BC%E3%82%AF%E3%81%AE%E6%84%8F%E5%91%B3)」を参照ください。

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

```


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

```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のキー名がクエリ変数名になります。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23101/d268f97a-2a66-13fe-1eb4-a57a145c6e97.png)


以上です。