Swagger UIを入れてみたものの、実装を直したのにドキュメントが更新されていなかった、という経験はありませんか。APIドキュメントの自動生成手段には大きく分けて Spring REST Docs と Springdoc OpenAPI の2つがあり、それぞれ得意分野が違います。本記事では両者の仕組みを整理して、どちらを選ぶべきかの判断軸を提示します。
2つの生成方式の違い
まず根本的な仕組みを押さえましょう。
Spring REST Docs はテスト駆動です。MockMvcやWebTestClient、REST Assuredで書いたテストの実行結果から、リクエスト・レスポンスのスニペット(Asciidoc断片)を生成します。テストが落ちればビルドも落ち、ドキュメントも更新されません。
Springdoc OpenAPI はアノテーション駆動です。実行時にコントローラのアノテーションとメソッドシグネチャをリフレクションで解析し、OpenAPI 3仕様のJSONを生成します。Swagger UIから対話的に叩けるのが特徴ですね。
なお、かつて主流だったSpringFoxはSpring Boot 3系に対応せず実質的にメンテナンス終了しています。新規プロジェクトの選択肢からは外して考えて問題ありません。
ドキュメントと実装の乖離リスク
どちらを選ぶかで一番悩むポイントが、ここだと思います。
REST Docsは「テストで叩いた実物」をそのままドキュメント化するので、嘘が書けません。レスポンスのフィールドを1つ増やしたのにドキュメントに反映し忘れる、ということが起こりにくい構造です。フィールド定義に漏れがあればdocument()がテストを失敗させてくれます。
一方Springdocは便利な反面、@Schemaの付け忘れや@Operationの説明が古いまま、といった乖離は実行時まで検知できません。テストとは独立して動くので、ドキュメントの正確性はレビュアーの目視に頼ることになります。
ただ、テスト文化がまだ育っていないチームでは、REST Docsの「テスト書かないと何も出ない」という性質はハードルになります。即効性ではSpringdocが圧勝です。
Spring REST Docsの最小構成
実際のコードを見てみましょう。Gradleの設定はこんな感じです。
plugins {
id 'org.asciidoctor.jvm.convert' version '3.3.2'
}
ext {
snippetsDir = file('build/generated-snippets')
}
dependencies {
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor'
}
test {
outputs.dir snippetsDir
}
asciidoctor {
inputs.dir snippetsDir
dependsOn test
}
テスト側はMockMvcにdocument()を挟むだけ。
@WebMvcTest(UserController.class)
@AutoConfigureRestDocs
class UserControllerDocsTest {
@Autowired MockMvc mockMvc;
@Test
void getUser() throws Exception {
mockMvc.perform(get("/users/{id}", 1))
.andExpect(status().isOk())
.andDo(document("users/get",
pathParameters(
parameterWithName("id").description("ユーザーID")
),
responseFields(
fieldWithPath("id").description("ID"),
fieldWithPath("name").description("氏名")
)
));
}
}
src/docs/asciidoc/index.adocからスニペットをinclude::で取り込めば、./gradlew asciidoctorでHTMLが生成されます。MockMvcの基礎が不安な方は Spring BootのMockMvcでコントローラをテストする もあわせてどうぞ。
Springdoc OpenAPIの最小構成
こちらは依存を1つ足すだけです。
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.5.0</version>
</dependency>
これで/swagger-ui.htmlがもう動きます。アノテーションで情報を補強しましょう。
@RestController
@RequestMapping("/users")
@Tag(name = "User", description = "ユーザー管理API")
public class UserController {
@Operation(summary = "ユーザー取得")
@GetMapping("/{id}")
public UserResponse get(
@Parameter(description = "ユーザーID") @PathVariable Long id
) {
return service.find(id);
}
}
グローバル設定はBeanで定義します。
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info().title("User API").version("v1"))
.components(new Components().addSecuritySchemes("bearer",
new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer")));
}
Swagger UI導入の基本は Spring BootでOpenAPI/Swagger UIを使う で詳しく扱っています。
比較表で整理
判断に使える観点で並べてみます。
| 観点 | Spring REST Docs | Springdoc OpenAPI |
|---|---|---|
| 生成タイミング | ビルド時(テスト実行時) | 実行時(リフレクション) |
| 実装との一致 | 強い(テスト連動) | 弱い(アノテーション任せ) |
| 初期導入コスト | 中(テスト前提) | 低(依存追加のみ) |
| 学習コスト | やや高い | 低い |
| 出力形式 | Asciidoc/HTML | OpenAPI仕様/Swagger UI |
| Try it out | なし(静的HTML) | あり |
| OpenAPI仕様出力 | 標準では不可(拡張で可能) | 標準 |
| CI連携 | テストが壊れたら自動検知 | 別途検知の仕組みが必要 |
| 公開向き | 静的ドキュメントとして配布 | 開発者ポータル・SDK生成 |
用途別の選び方
外部公開API・SDK配布が必要なら OpenAPI仕様がほぼ必須なので、Springdoc中心、または後述の併用パターンが現実的です。クライアントコード自動生成やAPI Gateway連携も仕様ベースで動きます。
金融・医療など厳密な仕様遵守が求められる社内API はREST Docsが向きます。「ドキュメントに書いてあることはテストで保証されている」という強い性質が効きます。
マイクロサービスで開発者ポータルを整備したい ケースは、各サービスがOpenAPI仕様を出す前提でSpringdocが扱いやすいです。BackstageなどのIDPとも相性が良いですね。
テスト文化がまだ薄い小規模チーム は、まずSpringdocで動くものを出して、必要になったら段階的にREST Docsへ寄せる流れがおすすめです。
併用パターン - restdocs-api-spec
「REST Docsの正確性が欲しいけどOpenAPI仕様も配りたい」という贅沢な要求には、 restdocs-api-spec という選択肢があります。epages-deがメンテしているサードパーティ拡張で、REST Docsのテストから直接OpenAPI 3.0仕様を吐き出せます。
plugins {
id 'com.epages.restdocs-api-spec' version '0.19.4'
}
dependencies {
testImplementation 'com.epages:restdocs-api-spec-mockmvc:0.19.4'
}
openapi3 {
title = 'User API'
version = '1.0.0'
format = 'yaml'
outputDirectory = 'build/api-spec'
}
./gradlew openapi3でopenapi.yamlが出力されるので、それをSwagger UIやRedocに食わせれば対話的なドキュメントになります。テストが品質を担保し、出力はOpenAPIという、いいとこ取りの構成です。
ただし学習コストはそれなりにかかります。チームにREST Docsを書ける人が複数いることが前提と考えたほうが良いです。
落とし穴とCIでの注意点
いくつか実プロジェクトで踏みやすい問題を挙げておきます。
REST Docsで意外と多いのが、ローカルで./gradlew asciidoctorだけ実行してテストをスキップしてしまうケース。古いスニペットでHTMLが組み上がってしまうので、CIでは必ずtestを先に走らせましょう。asciidoctorタスクにdependsOn testを入れておくと安全です。
SpringdocはSpring Securityとの組み合わせで/swagger-ui.htmlが401になりがちです。SecurityFilterChainで/swagger-ui/**と/v3/api-docs/**を明示的に許可する必要があります。本番では逆にこれらを閉じる設定も忘れずに。
リフレクションを多用するので、ネイティブイメージ(GraalVM)やプロキシ環境ではスキーマ生成に失敗することがあります。導入前に対象環境で一度ビルドを試しておくと安心です。
まとめ
選択の判断軸はシンプルです。「テスト文化があるか」と「外部公開するか」の2軸で考えれば、だいたい決まります。
- テスト文化あり × 社内API → REST Docs
- テスト文化あり × 外部公開 → restdocs-api-spec併用
- テスト文化薄い × どちらも → Springdocで開始
迷ったらSpringdocで小さく始めて、乖離が実害になってきたタイミングでREST Docsを部分導入する、というのが現実的な進め方だと思います。まずは CRUDチュートリアル で作ったような小さなAPIに両方試してみて、肌に合うほうを選んでみてください。