Eclipse MicroProfile OpenAPI を試してみた with WildFly Swarm

## 動機

WildFly Swarm 2018.3.3 で Eclipse MicroProfile 1.3 が追加されたということで、MicroProfile 1.3 の仕様のうちの一つである MicroProfile OpenAPI 1.0 を試してみたかった。

## OpenAPI Specification はかつての Swagger Specification

**OpenAPI Specification** (OAS) はかつて、**Swagger Specification** だったもので、[SmartBear社](https://smartbear.com/)のプロダクトである[Swagger](https://swagger.io/)固有とされていたものが、**OpenAPI Initiative** (Linux Foundation の共同プロジェクト) なるところに寄贈され、パブリックな仕様となっている。
OpenAPIの仕様に沿った YAML または JSON があれば、REST API のリファレンスが作れるし、各言語の REST API の実装を生成したりもできる。

## MicroProfile OpenAPI 1.0 とは
今回 MicroProfile 1.3 に追加された **MicroProfile OpenAPI 1.0** では JAX-RS Resource を作ると、その仕様が YAML または JSON として自動で提供されるようになった。
つまり、はじめはデザイン(ドキュメント)ファーストで OAS の YAML でAPIの仕様を決め、コードに落ちた後に仕様の変更をしたとしてもそれがダイレクトにAPIドキュメントに反映できるので、仕様の書き直しをすることがなくなる。

## やること。やったこと。

今回はコーディングファーストで WildFly Swarm 2018.3.3 で JAX-RS Resource を作り、OpenAPI準拠の仕様(YAML)が生成されることを確認してみる。

### プロジェクト生成

http://wildfly-swarm.io/generator/ にアクセスして、`Dependencies`のフォームに `MicroProrfile` と入力すると、`MicroProfile OpenAPI Fraction` がサジェストされるので、選択して、 "Generate Project" を押すと、MicroProfileが使える WildFly Swarm のプロジェクト(zipファイル) がダウンロードされる。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/57967/55a4b592-9a47-4f93-f352-696d4b7518f8.png)

### ビルドして起動してみる

ダウンロードされた zip を展開して、ビルドするだけで、すでに JAX-RS のアプリとして機能する。

```bash:ダウンロードしたzipを展開してビルド
unzip demo.zip
cd demo
mvn package
```

ビルドするとtarget配下には、 事項可能な JARファイル (Uber JAR) が出来上がっているので、javaコマンドで起動する。

```bash:ビルドしたアプリを起動
java -jar target/demo-swarm.jar
```

### 起動したアプリにアクセスしてみる

http://localhost:8080/hello にアクセスると、`Hello from WildFly Swarm!`が得られる

```bash
$ curl -i http://localhost:8080/hello                                                                                                  [03/24 15:15]
HTTP/1.1 200 OK
Connection: keep-alive
Content-Type: text/plain;charset=UTF-8
Content-Length: 25
Date: Sat, 24 Mar 2018 06:17:20 GMT

Hello from WildFly Swarm!
```

実はもうこの時点で、このAPIの仕様は公開されている。
http://localhost:8080/openapi にアクセスすると、OpenAPI Specification 準拠のYAML形式のファイルが得られる。
これが**APIの仕様書**となる。

```
$ curl -i http://localhost:8080/openapi
---
openapi: 3.0.1
info:
  title: MicroProfile OpenAPI with WildFly Swarm
  description: This is a sample server for a MicroProfile OpenAPI.
  version: 1.0.0-SNAPSHOT
paths:
  /hello:
    get:
      responses:
        200:
          content:
            text/plain: {}
```

### 人が見て分かりやすいページにする

これだけでAPIの仕様として読めなくもないが、人に優しくないので、ちゃんとドキュメントとして読める形にしてあげることにする。
いろいろ調べた結果、[ReDoc](https://github.com/Rebilly/ReDoc) が良さそうだった。[Docker Engine](https://docs.docker.com/engine/api/v1.25/) の APIリファレンス もこれを使用しているようだ。

#### JAX-RSのパスを変更する

HTMLを置きたいけど、デフォルトではルートパスがJAX-RSのパスとしているため、`/api`に変更する。

```java:JaxRsActivator.java
// package, import は省略

@ApplicationPath("api")
public class JaxRsActivator extends Application {

}

```

これにより、`/hello`のリソースは`/api/hello`に変わる。

#### ReDocのHTMLを作る

[ReDocのREADME.md](https://github.com/Rebilly/ReDoc/blob/master/README.md)にも書いてあるが、以下のように一つHTMLファイルをおいてあげる。

```html:src/main/webapp/index.html
<!DOCTYPE html>
<html>
    <head>
        <title>ReDoc</title>
        <!-- needed for adaptive design -->
        <meta charset="utf-8"/>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
        <!--
        ReDoc doesn't change outer page styles
        -->
        <style>
            body {
                margin: 0;
                padding: 0;
            }
        </style>
    </head>
    <body>
    <!-- ここで /openapi を参照するようにしてあげる！ -->
    <redoc spec-url='/openapi'></redoc>
    <script src="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js"></script>
</body>
</html>
```

あとは、同様にビルドしなおして、起動してあげれば
。
http://localhost:8080/api/hello でJAX-RS リソースが提供されているし、
http://localhost:8080/openapi で OpenAPI Specification 準拠のYAML見れるし
http://localhost:8080/ ではカッコイイAPIドキュメント出来上がってる！

![image.png](https://qiita-image-store.s3.amazonaws.com/0/57967/25fb6dc1-cd83-391f-9957-02db2835d888.png)

タイトルやライセンス、コンタクト情報など、さまざまな情報を設定したい場合 `src/main/resources/META-INF/openapi.json` を [OpenAPI Specification に従った形式](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#specification) で修正してあげればページにも反映される。

### さらにドキュメンテーションを充実させるには

MicroProfile OpenAPI では様々な[アノテーション](https://github.com/eclipse/microprofile-open-api/blob/master/spec/src/main/asciidoc/microprofile-openapi-spec.adoc#annotations)が用意されており、適切にJAX-RS Resource につけてあげれば、OpenAPI Specification 準拠の情報を付加することができる。

さらに、ReDoc に対応する [Extension](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-examples) を設定してあげることで、APIのクライアント用のサンプルコードを生成する機能を付加したり、`POST`する JSON の Example などの情報が付加できるようだ。

## デモ用に作ったコード

GitHub https://github.com/sightseeker/wildfly-swarm-mp-demo に上げていますので、すぐに試したい方はこちらをどうぞ。

### Files

ファイルはたったこれだけ。

```
├── pom.xml
└── src
    └── main
        ├── java/com/sightseekerstudio/wildflyswarmmpdemo/rest
        │   ├── HelloWorldEndpoint.java
        │   └── JaxRsActivator.java
        ├── resources
        │   └── META-INF
        │       └── openapi.json
        └── webapp
            └── index.html
```