はじめに
RESTful サービスを実現しようと思うと、設計やテストそれに仕様の公開が必要になる。
JAX-RS で開発するプロジェクトで Swagger を活用する。
Swagger(OpenAPI) を使うメリット
RESTful サービスは利用者向けの API のドキュメントが重要になる。
サービスごとにドキュメントの形式が違うと利用者はそれぞれの見方を覚えなければならず、無駄な時間と労力がかかる。
そこで、OpenAPI という仕様があり、それを使って実際に操作できるツール群が Swagger という位置づけ。
サービスを提供するが側として、まず API を設計してそれをトップダウンで実装出来れば理想だが、往々にしてアジャイル開発のように実装のほうが先になるケースも多い。
そういった場合、実装からボトムアップで OpenAPI の仕様書を作成できれば非常にありがたい。
そういった機能があるのも Swagger の良い点である。
前提の環境
ここで使う環境は下記の通り
- 開発ツールは Eclipse を使う
- JAX-RSの仕様の実装として Jersey を使う
- WEBサーバーは Tomcat を使う
この章では、Jersey プロジェクトに Swagger を組み込む方法だけを簡単に説明する。
アプリケーションの機能は単純に「Get it!」を文字列で返すだけの API。
Jersey の Eclipse におけるプロジェクトの作成は 前章 で解説している。
web.xml は使わない方法を前提にしている。
参考までに Eclipse の構成としては下記の通り。
- Eclipse のプロジェクト名を"jersey2"
- API の実装は、パッケージ "app1" 配下に MyResource.java
- アプリケーションを MyApplication.java
- API のパスを"/webapi"
とした。
使用する Swagger の Maven アーティファクト
Maven で探してみると、同じようなものがいくつもあり、どれが最適なのか良く解らない。
最終的には2つのアーティファクトに絞った。
- swagger-jaxrs2(swagger-jaxrs2-jakarta)
- swagger-jersey2-jaxrs
実はどちらも Swagger Core を使うという意味では機能としては同じ。
何が違うかと言うと、(2.)は Jersey2 に特化している。
(1.)は実装に特化せず汎用で、パッケージの名前空間が javax と jakarta に分かれている。
具体的には Tomcat10 以降で使うには、jakarta を使う必要がある。
つまり、特別な理由が無い限り(1.)を使う。
出来る事は JAX-RS 仕様のアノテーション(注釈)を読み取って openapi.json または openapi.yaml を自動生成してくれる。
Swagger-UI を使って、生成される URL を参照すれば、定義が視覚化されるという具合である。
Swagger Core を使う
詳しくは
GitHub Swagger Core
Chrome の日本語自動翻訳でも十分理解できる内容。
要点は、
Core 自体は、バージョン 2.1.7 以降は jakarta 名前空間もサポートしている。
具体的な使用方法は次を参照。
Swagger-2.X---Getting-started
Maven の設定
Maven の設定は、pom.xml に以下を追加。(Tomcat10の場合)
<dependencies>
...
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2-jakarta</artifactId>
<version>2.2.22</version>
</dependency>
名前空間の各依存性については解りにくいので表にすると、
JavaEE パッケージ名 | Tomcat | Jersey | Swagger artifactId |
---|---|---|---|
javax.* | 9 以前 | 2.x 以前 | swagger-* |
jakarta.* | 10 以降 | 3.0 以降 | swagger-*-jakarta |
利用する環境によって横のバージョンを合わせないと上手く動かない。
これ以外に JavaSE のバージョンも関係するが、単純に表には出来ない。
アプリケーションへの組み込み
アプリケーションに Swagger の解析機能を組み込む。
一般的な JAX-RS 実装では、
@ApplicationPath("/webapi")
public class MyApplication extends Application {
public Set<Class<?>> getClasses() {
Set<Class<?>> s = new HashSet<Class<?>>();
s.add(MyResource.class);
s.add(OpenApiResource.class);
return s;
}
}
Jersey に関しては、ResourceConfig を使っても良い。
@ApplicationPath("/webapi")
public class MyApplication extends ResourceConfig {
public MyApplication() {
packages("app1.jersey2");
OpenApiResource openApiResource = new OpenApiResource();
register(openApiResource);
}
}
要は、OpenApiResource クラスを追加する。
最低限の設定はこれだけで良い。
実行してみる
実行する前に、Tomcat での URL の関係だが、
@ApplicationPath("/webapi") は、URL の位置では basePath になる。
Tomcat のコンテキストパス("jersey2")は host 名に含まれる。
実行したら、
http://localhost:{ポート番号}/{コンテキストパス}/{basePath}/openapi.yaml(または.json)
にアクセスすればファイルが取得できる。
具体的に、Tomcat のポートを 8081 とした場合は以下の通り。
http://localhost:8081/jersey2/webapi/openapi.yaml
ブラウザでアクセスするとファイルがダウンロードされる。
Swagger-UI で参照する
後は、Swagger-UI で先ほどの URL にアクセスすれば良い。
と言いたいところだが、Swagger-UI を別環境で起動してもそのままでは、CORS の為参照できない。
CORS はクロスサイト攻撃をブロックする為にブラウザが持つセキュリティ機能。
サーバー側の設定でクロスサイトによる接続を許可することは出来る。
Tomcat での CORS 許可は制限があるし面倒でもある。
実運用では Apache 等のフロントを用意するだろうから余計な事はしないで、
同じサーバー(Tomcat)上で起動するのが良いだろう。
Swagger-UI はシングルページ・アプリケーションなので設置は簡単。
GitHub swagger-ui
から最新版をダウンロードし、解凍した dist フォルダの中身を webapps 配下にコピーすれば良い。下はその例。
プロジェクトを実行し、ブラウザの URL に
http://localhost:8081/jersey2/swagger-ui/
を指定すれば Swagger-UI が起動できる。
openapi.yaml(またはjson)の URL を指定すれば、
が表示される。
些細な事だが、Swagger-UI のデフォルトの URL を変更したいと思う人は多いと思う。
何故かピンとくる方法が見つからない。
将来も適用できるか分からないが、面倒なので、
swagger-initializer.js
を直接変更してしまうのが一番簡単。
window.onload = function() {
container
:
window.ui = SwaggerUIBundle({
// url: "https://petstore.swagger.io/v2/swagger.json",
url: "http://localhost:8081/jersey2/webapi/openapi.json",
:
};
変わらない場合、たまにブラウザの JavaScript のキャッシュが残っている場合があるのでクリアする。
Tomcat のコンテキストパスの扱い
Swagger-UI が起動して OpenApi への参照も出来たが、困った問題がある。
Swagger 上で「Try it out」で実行すると、下記の通りエラーになる。
デフォルトでは Tomcat のコンテキストパスからの相対では無く、サーバー(localhost:8081)からの相対をエンドパスとしてしまう。
なので、openapi.yaml(json) にサーバーパスの設定が必要になる。
単なるファイルであれば、server のパスを設定すれば良いだけだが、自動で生成されているので別途プログラムで指示する必要がある。
アノテーションで Swagger の生成定義を指定する
いくつかやり方があるが、最も簡単な方法は、Swagger Core のアノテーションを使う事だ。
ここでは、ついでにタイトルやコメントも変更する。
解り易く MyApplication.java に記述したが、MyResource.java に書いても構わない。
@ApplicationPath("/webapi")
@OpenAPIDefinition(
info = @io.swagger.v3.oas.annotations.info.Info(
title = "Jersey Sample API",
version = "0.0",
description = "Swagger Core で定義を生成",
license = @io.swagger.v3.oas.annotations.info.License (name = "Apache 2.0", url = "http://foo.bar"),
contact = @Contact(url = "http://hoge.com", name = "yamada", email = "yamada@hoge.com")
),
servers = {
@Server(
description = "tomcat10",
url = "/jersey2" )
}
)
反映されて servers に /jersey2 が表示される。
「Try it out」も今度は問題なく実行できる。
最後に
当初もっと複雑なサンプルを使うつもりだったが不明な点が多く、基本に戻ってまずは簡単なものにした。