GraphQL×Java入門 Mutation編

## はじめに
前回は、JavaでのQueryの実装例を紹介したので、今回はMutationを紹介します。
ただ、JavaでGraphQLの実装してもらうときのポイントとなるところを紹介するのがメインなので、ソースコードを作り込んでいるわけではないので、実務でそのまま使用するのは避けてくださいmm
(時短で結構適当にロジックや例外処理書いてあります)

## 環境

・SpringBoot:3.3.2
・Java:17
・GraphQL:22.1

## ソースコード

[GraphQL Sample](https://github.com/kehuka11/graphql_sample)

## 実装

### 1データ登録

**スキーマ**

~~~sql
type Mutation {
    registerBook(title: String!, author: AuthorInput!): Book!
}

type Book {
    id: ID!
    title: String!
    author: Author
}

input AuthorInput {
    id: ID!
    firstName: String!
    lastName: String!
}
~~~

**コントローラ**

~~~java
@Controller
public class BookController {


    private final BookService bookService;

    public BookController(BookService bookService) {
        this.bookService = bookService;
    }

    @MutationMapping
    public BookResponse registerBook(@Argument("title") String title, @Argument("author") Author author) {

        Book book = bookService.registerBook(title, author);

        return new BookResponse(book.id().getId().toString(), book.title(), book.author());

    }

}
~~~


 **ユースケース**

 ~~~java
@Service
public class BookService {

    private final BookRepository bookRepository;

    private final AuthorRepository authorRepository;

    public BookService(BookRepository bookRepository, AuthorRepository authorRepository) {
        this.bookRepository = bookRepository;
        this.authorRepository = authorRepository;
    }

    public Book registerBook(String title, Author author) {
        UUID uuid = UUID.randomUUID();
        Book book = new Book(new BookId(uuid.toString()), title, author);

        if (!authorRepository.existById(author.id())) {
            authorRepository.register(author);
        }

        bookRepository.registerBook(book);

        return book;
    }

}

 ~~~

 **リポジトリ**

 ~~~java
public interface BookRepository {

    void registerBook(Book book);

}

@Repository
public class BookRepositoryImpl implements BookRepository {
    @Autowired
    DSLContext dslContext;

    @Override
    public void registerBook(Book book) {
        dslContext.insertInto(BOOK)
                .set(BOOK.ID, book.id().getId().toString())
                .set(BOOK.TITLE, book.title())
                .set(BOOK.AUTHORID, book.author().id())
                .execute();
    }

}
 ~~~

 **クエリ**

 ~~~graphql
mutation {
  registerBook(title: "mutationTest", 
  author: {
      id: "author-1",
      firstName: "first-test-name"
      lastName: "last-test-name" 
  }) {
    id 
    title
    author {
      id
      firstName
      lastName
    }
  }
}
 ~~~

 **実行結果**

 ~~~json
{
    "data": {
        "registerBookV2": {
            "id": "bf0892e1-5d63-4b42-aae5-50001130af4d",
            "title": "mutationTest",
            "author": {
                "id": "author-1",
                "firstName": "first-test-name",
                "lastName": "last-test-name"
            }
        }
    }
}
 ~~~


・コントローラクラス
  Query書いているときは`@QueryMapping`のアノテーションを付与していたが、Mutationのときは`@MutationMapping`を付与すればOK

  ・スキーマ

  `type mutation`でコマンド定義

  リクエストでオブジェクト指定したい場合は、`input`でデータ構造を定義

  その他はQuery定義するときと変わらない。


  ### 複数データ登録


  **スキーマ**

  ~~~graphql
type Mutation {
    registerBookV2(bookList: [BookInput]!): Int!
}

input BookInput {
    title: String!
    author: AuthorInput!
}

input AuthorInput {
    id: ID!
    firstName: String!
    lastName: String!
}
  ~~~

  **クエリ**

  ~~~graphql
mutation {
  registerBookV2(bookList: [
    {
      title: "title1"
      author: {
        id: "author-1",
        firstName: "first-author1"
        lastName: "last-author1"
      }
    },
    {
        title: "title2"
        author: {
          id: "author-2",
          firstName: "first-author2"
          lastName: "last-author2"
        }
    }
  ])

}

  ~~~

  **結果**

  ~~~json
{
    "data": {
        "registerBookV2": 2
    }
}
  ~~~

  リストで受け取るコントローラ用意して、スキーマでは、リストを指定するコマンドを定義すれば、複数データ登録もできます。

  ちなみに以下のように複数回コマンド実行して、複数データ登録することもできます。

**クエリ**

  ~~~graphql
  
mutation {
  book1: registerBookV2(bookList: {
      title: "title1"
      author: {
        id: "author-1",
        firstName: "first-author1"
        lastName: "last-author2"
      }
  })

  book2: registerBookV2(bookList: {
      title: "title1"
      author: {
        id: "author-1",
        firstName: "first-author1"
        lastName: "last-author2"
      }
  })
}

  ~~~

  **結果**

  ~~~json
{
    "data": {
        "book1": 1,
        "book2": 1
    }
}
  ~~~

  別々のコマンド実行を1度のリクエストで完結したいときは、使用するのだろうが、1度のリクエストで同じコマンドを複数回実行することは、実際の業務ではほとんどないと思います。

## さいごに

今回はJavaでのMutation実装例を紹介させてもらいました。
次はエラーハンドリング周りの紹介をしますー

## 参考文献

https://spring.pleiades.io/spring-graphql/reference

https://graphql.org/learn/schema/#union-types