今回は https://quarkus.io/guides/spring-di これらのチュートリアルを参考に簡単な API を作成しました。

Quarkus Spring Extension で簡単な API を作成してみる

2021年1月10日

Mandrel: Red HatのQuarkusビルド用のGraalVMのコミュニティディストリビューション - 赤帽エンジニアブログ

今回は https://quarkus.io/guides/spring-di これらのチュートリアルを参考に簡単な API を作成しました。

今 Quakus の公式ではこんな感じで Spring boot の互換性という事で Extension for Spring といったものが公開されています。 

Quakus は起動も早くメモリ使用量も少ない、割と最近出てきた人気のフレームワークだけど学習コストなどを懸念して手を出し辛かった。。。そんな人も慣れた Spring boot と同じ様に開発していけるなら敷居も低くなるのでは?

API 概要

今回作るのはこんなドメインモデルを持った書籍管理 API。練習用のなんてことのない CRUD をやります。3層構造で作ります。

public class Book {

  private Integer id;

  private String title;

  private String author;

  private Integer cost;
}

Dependency

maven 使ってます。

今回使ってみるのはこの3つ。pom にこいつらを追加します。

<dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-spring-di</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-spring-web</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-spring-data-jpa</artifactId>
    </dependency>

Controller

CRUD と言ってもどれもそんな変わらないので今回は GET と POST だけ作りました。 Spring を使っている人なら見慣れたアノテーションが使われています。

@RestController
@RequestMapping("book")
public class BookController {

  @Autowired
  private BookService bookService;

  /**
   * 指定した id の本を取得するためのエンドポイントです。
   *
   * @param bookId 取得したい本の id
   * @return 取得した本
   */
  @GetMapping(path = "/{id}")
  @Produces(MediaType.APPLICATION_JSON)
  public BookResponse getBook(@PathVariable("id") String bookId) {
    Book book = bookService.getBook(Integer.parseInt(bookId));
    return BookResponse.of(book);
  }

  /**
   * 指定した本を登録するためのエンドポイントです
   *
   * @param request 登録したい本のリクエスト
   * @return 登録した本
   */
  @PostMapping
  @Produces(MediaType.APPLICATION_JSON)
  public CreateBookResponse createBook(CreateBookRequest request) {
    Book book = bookService.createBook(request.toModel());
    return CreateBookResponse.of(book);
  }
}

Service

@Service
@Configuration
public class BookServiceImpl implements BookService {

  @Autowired
  BookRepository bookRepository;

  private static final String LOCAL_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";

  DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(LOCAL_DATE_TIME_FORMAT);


  /**
   * {@inheritDoc}
   */
  @Override
  public Book getBook(Integer bookId) {
    Optional<BookEntity> optionalBookEntity = bookRepository.findById(bookId);

    if (optionalBookEntity.isPresent()) {
      BookEntity bookEntity = optionalBookEntity.get();
      return Book.builder()
                 .id(bookEntity.getId())
                 .title(bookEntity.getTitle())
                 .author(bookEntity.getAuthor())
                 .cost(bookEntity.getCost())
                 .build();
    } else {
      return null;
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public Book createBook(Book book) {
    BookEntity bookEntity =  BookEntity.builder()
                                       .cost(book.getCost())
                                       .title(book.getTitle())
                                       .author(book.getAuthor())
                                       .createdAt(Timestamp.valueOf(LocalDateTime.now().format(dateTimeFormatter)))
                                       .updatedAt(Timestamp.valueOf(LocalDateTime.now().format(dateTimeFormatter)))
                                       .build();

    BookEntity createdEntity = bookRepository.save(bookEntity);

    return Book.builder()
               .id(createdEntity.getId())
               .title(createdEntity.getTitle())
               .author(createdEntity.getAuthor())
               .cost(createdEntity.getCost())
               .build();
  }
}

Repository

Spring data jpa を使っています。現在実際のプロジェクトでも Quakus を使っていますが開発を始めた当初はこんな Extension はなかったので普通に Java EE の jpa を使っています。簡単な CRUD ならデータアクセスの部分、Repository を書かなくても良いので楽です。

public interface BookRepository extends CrudRepository<BookEntity, Integer> {

}

はい、こんな感じで Spring で書くのと全く同じ様に Quarkus でも作っていくことが可能です。細かいところは端折っていますがこれでもう Quarkus として起動できました。 

test は QuarkusTest で作りました。 以前は QuarkusTest で Mockito も使えなかったので自分達で Mock を作成していましたが今は使える様になってます。

@QuarkusTest
class BookControllerTest {

  @InjectMock
  BookService bookService;

  @Test
  void test_指定したidで本を取得できる() {

    when(bookService.getBook(1)).thenReturn(Book.builder()
                                                .id(1)
                                                .title("java 入門")
                                                .author("hoge")
                                                .cost(5000)
                                                .build());

      given()
        .when()
          .pathParam("id", "1")
          .get("/book/{id}")
        .then()
           .statusCode(200)
           .body("id", equalTo(1))
           .body("title", equalTo("java 入門"))
           .body("cost", equalTo(5000));

      verify(bookService).getBook(1);
  }

  @Test
  void test_POSTでリクエストして本が登録できる事() {

    when(bookService.createBook(Book.builder()
                                    .title("swift 入門")
                                    .author("huga")
                                    .cost(3000)
                                    .build()))
        .thenReturn(Book.builder()
                        .id(1)
                        .title("swift 入門")
                        .author("huga")
                        .cost(3000)
                        .build());


    given()
        .when()
        .contentType("application/json")
        .body(marshalToJson(CreateBookRequest.builder()
                                             .title("swift 入門")
                                             .author("huga")
                                             .cost(3000)
                                             .build()))
        .post("/book")
        .then()
        .statusCode(200)
        .body("message", equalTo("Book successfully created!"))
        .body("title", equalTo("swift 入門"))
        .body("cost", equalTo(3000));
  }

}

コードは git にもアップしていますのでそちらも参考にして下さい。

https://github.com/tsukasaM/book-quarkus-spring-extension

まとめ

以上です。今回は Quarkus の Spring Extension を使って簡単な API を作成しました。主な実装箇所は 通常の Spring boot と同じシンタックスで書ける事がわかりました。 次回は 元々 Spring で作っていた API をコードをいじらずに Quakus で起動できるかやってみたいと思います。(たぶん)

学習書籍


Quarkus Cookbook【電子書籍】[ Alex Soto Bueno ]

Spring Boot2徹底活用 現場至上主義 [ 廣末丈士 ]

【中古】 Apache Maven2.0入門 Java・オープンソース・ビルドツール /野瀬直樹,横田健彦【著】 【中古】afb