スポンサーリンク

Spring BootでSwaggerを3分導入!springdoc-openapi入門

スポンサーリンク
この記事は約22分で読めます。
スポンサーリンク

「Swagger入れといて〜」って言われて、何を入れればいいの?って固まったこと、ありませんか?
依存関係を追加したのにSwagger UIが出ない
、URL開いても404で詰む、さらにSpring Security入ってたらログイン画面に飛ばされる…新人あるあるです。

でも大丈夫です。
この記事は、最短で“動く”ところまで持っていくのに全振りしています。
今日やることは、これだけです👇

  • Swagger UIを表示できるようにする(まずは画面を出して勝つ)
  • 最低限の説明を書けるようにする(「何するAPI?」が1行入る)
  • 本番ではOFFにできるようにする(安心して運用できる)

「とにかく今すぐ動かしたい(Do)」も、「仕組みもざっくり知りたい(Know)」も、両方かないます。
まずは用語の混乱を1分で止めてから、依存関係追加 → 起動 → URLを開くでサクッと成功体験いきましょう。

  1. まずこれだけ:springdocとSwaggerの関係
    1. OpenAPIは「説明書の型」、Swagger UIは「見やすい画面」
    2. Spring Bootでの役割分担(自動生成/表示)
    3. この記事のゴール(最短で動かす→最低限整える)
  2. 3分で動く!最短導入(Maven/Gradle)
    1. 依存関係はこれ(WebMVC / WebFluxの選び方)
    2. 起動して確認する「2つのURL」
    3. コピペ用:最小Controllerを1本作る
    4. バージョン選びで迷わないコツ(互換表の見方)
  3. 404で詰まらない:Swagger UIのURL早見表
    1. まず試すURL(よくある順)
    2. context-pathを変えた時の落とし穴
    3. 静的index.htmlとぶつかる問題
    4. 「APIは出るのにUIだけ無い」切り分け
  4. 最低限のカスタムだけ先にやる(やりすぎない)
    1. タイトル/説明/バージョンだけ整える
    2. サーバーURL(開発・検証)を表示したい時
    3. タグで見やすくする(画面で迷子にしない)
  5. 書き方テンプレ:説明文・パラメータ・レスポンス例
    1. まずはこれだけ:@Operationで1行説明
    2. パラメータの説明(必須/任意・例・注意)
    3. レスポンスの例(成功・失敗の2つは書く)
    4. エラー設計(400/401/404/500)を同じ形で書く
    5. 「内部用は隠す」基本(非表示のやり方)
  6. Spring SecurityでSwaggerが見れない問題を解決
    1. Swagger UIだけ通す(permitの最小ルール)
    2. Bearer(JWT)入力を出す(Authorizeボタン)
    3. CSRF・ログイン画面に飛ぶ時の考え方
  7. 本番でSwagger UIを出していい?安全な出し分け
    1. 結論:原則「開発だけON」が安心
    2. UIだけOFF/API定義もOFF(どっちを止める?)
    3. profileで切り替える(dev/prodの例)
    4. 代わりに「定義ファイルを配る」選択肢
  8. よくあるエラー集(症状→原因→直し方)
    1. 404になる(URL・依存関係・パス競合)
    2. 真っ白/定義を読めない(api-docs側の確認)
    3. No operations defined(Controller検出・パッケージ)
    4. 起動失敗(依存の不一致・バージョン)
    5. CORSで叩けない(別ポート・別ドメイン)
  9. 最後のチェックリスト&次の一歩(CTA)
    1. まず合格ライン(新人の提出OK)
    2. チームで育てる改善ロードマップ
    3. 参考リンク(公式/互換表/サンプル)
  10. よくある質問
スポンサーリンク

まずこれだけ:springdocとSwaggerの関係

OpenAPIは「説明書の型」、Swagger UIは「見やすい画面」

まず用語で迷子になりがちなので、たとえ話で考えましょう。

OpenAPIは「説明書のテンプレ(型)」です。
APIが「何を受け取って、何を返すか」を同じ形で書けるルール、みたいなものです。

一方でSwagger UIは「その説明書を“見やすい画面”で表示するやつ」です。
説明書そのものじゃなくて、読むためのビューアだと思ってください。

Spring Bootでの役割分担(自動生成/表示)

Spring Boot側で大事なのは、「説明書を作る担当」です。そこで出てくるのが springdoc-openapi
コントローラを見て、OpenAPIの定義(JSON)を自動で作って、ついでにSwagger UIで見せてくれます。

結論:Spring BootでSwagger UIを出したいなら、基本はspringdoc-openapiを入れればOKです。

この記事のゴール(最短で動かす→最低限整える)

この記事は、①最短導入でまず表示 → ②最低限の説明を整える → ③Securityで見れない問題 → ④本番ではOFF → ⑤トラブル即解決、の順で進みます。

学習・確認ツール(紹介するならこの辺)

  • Swagger Editor:無料(OpenAPIを先に触って感覚つかむ用)
  • Stoplight Studio:無料〜有料(チームで育てる時に便利な枠)
SwaggerEditor
SwaggerEditor
OpenAPI Design & Documentation Management Tool | Stoplight
With Stoplight, you can create OpenAPI descriptions, documentation, and mock servers much faster than other API tools — ...

3分で動く!最短導入(Maven/Gradle)

依存関係はこれ(WebMVC / WebFluxの選び方)

まずは「自分どっち?」をここで決めちゃいましょう。使ってるstarter名で判断するのが一番ラクです。

いま入ってるもの選ぶspringdoc依存関係(UIあり)
spring-boot-starter-webWebMVCspringdoc-openapi-starter-webmvc-ui
spring-boot-starter-webfluxWebFluxspringdoc-openapi-starter-webflux-ui

Maven(どっちか1つだけ入れてください)

<dependency>
  <groupId>org.springdoc</groupId>
  <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
  <version>2.8.14</version>
</dependency>

<!-- WebFluxならこっち
<dependency>
  <groupId>org.springdoc</groupId>
  <artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
  <version>2.8.14</version>
</dependency>
-->

Gradle(どっちか1つだけ)

implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.14"
// WebFluxなら:implementation "org.springdoc:springdoc-openapi-starter-webflux-ui:2.8.14"

起動して確認する「2つのURL」

起動したら、見るのはこの2つだけです(ここで勝ちます)。

  • API定義(まずこっちが最優先)http://localhost:8080/v3/api-docs
    → JSONが出たら ほぼ勝ち です。
  • Swagger UIhttp://localhost:8080/swagger-ui.html
    → だいたい .../swagger-ui/index.html に案内されます。

コピペ用:最小Controllerを1本作る

「何も出ない…」を防ぐために、GETを1本だけ作ります。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
  @GetMapping("/hello")
  public String hello() {
    return "hello";
  }
}

これでSwagger UIに /hello が見えたら、導入は完了です。

バージョン選びで迷わないコツ(互換表の見方)

バージョンで沼りがちなので、ルールを固定します。

  • Spring Boot 3系なら springdoc 2.x(公式の互換表に載ってます)
  • Spring Boot 2系なら springdoc 1.x(最後のOSSは1.8.0)
  • そして基本は「互換表にある範囲で、最新の安定版」を選べばOKです。
    ※Maven Centralには3.0.0もありますが、依存関係的にSpring Boot 4系向けの匂いが強いので、Boot 3の人はまず2.xでいきましょう。

開発支援ツール(紹介するならこの辺のカテゴリ/価格感)

  • IDE:IntelliJ IDEA(無料Community〜有料Ultimate)
  • APIテスト:Postman(無料〜)

Swagger UIで試しつつ、外部ツールでも叩ける状態にしておくと提出が強いです。

業界をリードするプロ仕様の Java および Kotlin 開発向け IDE
IntelliJ IDEA は JetBrains が提供するプロ仕様の Java および Kotlin 開発向け IDE です。 快適さを追求した設計となっており、高い生産性と質の高いコードを実現し、最先端のテクノロジーをサポートしている...
Postman: The World's Leading API Platform | Sign Up for Free
Accelerate API development with Postman's all-in-one platform. Streamline collaboration and simplify the API lifecycle f...

404で詰まらない:Swagger UIのURL早見表

まず試すURL(よくある順)

迷ったら、この順でOKです(上から順番に叩くのがコツです)。

目的まず試すURL期待するもの
API定義/v3/api-docsJSONが出る(出たら生成は成功)
UI/swagger-ui.htmlUIにリダイレクトされること多め
UI本体/swagger-ui/index.html画面が出る

context-pathを変えた時の落とし穴

server.servlet.context-path=/api みたいに付けてたら、URLも 全部先頭に/api が付きます。
例:/api/v3/api-docs/api/swagger-ui/index.html です。ここ、めっちゃ忘れがちです。

静的index.htmlとぶつかる問題

React/VueのSPAを置いてて、/ が常に index.html を返す設定だと、Swaggerをルート配下に寄せた時にUIが飲み込まれます。
対策はシンプルで、Swaggerは/swagger-ui/配下に置く(=変にパスをいじらない)か、SPA側のルーティングから除外します。

「APIは出るのにUIだけ無い」切り分け

  • /v3/api-docs が出る → 生成はOK、次はUI側を疑う
    • UI付きの依存(…-ui)を入れてる?
    • WebMVC/WebFluxを取り違えてない?
    • springdoc.swagger-ui.enabled=false にしてない?
  • /v3/api-docs も出ない → まず依存関係かController検出を見直す(次のエラー集でも触れます)

最低限のカスタムだけ先にやる(やりすぎない)

タイトル/説明/バージョンだけ整える

まずはここだけでOKです。これが入ってるだけで「誰向けのAPIで、今どの版?」が一瞬で伝わって、チーム提出で恥ずかしくないです。

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class OpenApiConfig {
  @Bean
  public OpenAPI openAPI() {
    return new OpenAPI()
      .info(new Info()
        .title("サンプルAPI")
        .description("社内向けの検証用APIです。まずはGETから。")
        .version("v1"));
  }
}

サーバーURL(開発・検証)を表示したい時

server URLは「必要な時だけ」でOKです(環境で変わるので、無理に固定すると逆に混乱します)。別環境で試す人が多い時だけ入れましょう。

import io.swagger.v3.oas.models.servers.Server;
// openAPI()の中で…
.addServersItem(new Server().url("http://localhost:8080"))

タグで見やすくする(画面で迷子にしない)

エンドポイントが増えると迷子になります。Controllerごとにタグを付けるのが手っ取り早いです。

import io.swagger.v3.oas.annotations.tags.Tag;

@Tag(name = "ユーザー", description = "ユーザー関連のAPI")
@RestController
class UserController { /* ... */ }
The Best API Documentation Tool
OpenAPI-generated documentation tool with 24k+ stars on Github - make APIs your company's superpower.
Scalar ??? Document, Discover and Test APIs
Document, Discover and Test APIs with Scalar.

書き方テンプレ:説明文・パラメータ・レスポンス例

まずはこれだけ:@Operationで1行説明

Swaggerは「説明があるだけ」で一気に読みやすくなります。まずは1行だけ入れましょう。

@Operation(summary = "ユーザーを1人取得します(社内ツール用)")
@GetMapping("/users/{id}")
public UserResponse getUser(@PathVariable Long id) { ... }

1行テンプレ(迷ったらこれ)
「何をする?/誰向け?/注意は?」の順です。

パラメータの説明(必須/任意・例・注意)

次はパラメータです。意味・必須・例・制約が入ると親切です。

@GetMapping("/users/{id}")
public UserResponse getUser(
  @Parameter(description = "ユーザーID(1以上)", example = "123", required = true)
  @PathVariable Long id,

  @Parameter(description = "詳細を含めるか", example = "true", required = false)
  @RequestParam(required = false) Boolean detail
) { ... }

レスポンスの例(成功・失敗の2つは書く)

最低でも「成功」と「失敗」を1個ずつ置くと、使う人が迷いません。

@Operation(summary = "ユーザーを1人取得")
@ApiResponses({
  @ApiResponse(responseCode = "200", description = "成功"),
  @ApiResponse(responseCode = "404", description = "見つからない")
})
@GetMapping("/users/{id}")
public UserResponse getUser(...) { ... }

例(見た目のイメージ):

  • 成功:{ "id": 123, "name": "Taro" }
  • 失敗:{ "code": "NOT_FOUND", "message": "ユーザーがいません" }

エラー設計(400/401/404/500)を同じ形で書く

ここが超大事です。エラーは毎回バラバラにしないで、同じ形にします。

{
  "code": "BAD_REQUEST",
  "message": "入力が不正です",
  "details": ["idは1以上にしてください"]
}

最低セットはこれでOKです:

  • 400 入力ミス(必須不足・形式違い)
  • 401 ログイン/トークン不正
  • 404 対象なし
  • 500 サーバー側の事故

実装は @RestControllerAdvice でまとめると、説明も運用もラクになります(「全部この形で返す」が守れます)。

「内部用は隠す」基本(非表示のやり方)

管理用やデバッグ用は、最初から見せないのが安全です。

@Hidden
@GetMapping("/internal/health-detail")
public String internalOnly() { ... }

// もしくは
@Operation(summary = "内部用", hidden = true)

API仕様のレビュー/共有ツール(紹介するならこのカテゴリ)

  • Bump.sh(無料〜有料)みたいな「OpenAPIを共有してレビューできる系」を入れると、フロント・QAとも話が早くなります。

Spring SecurityでSwaggerが見れない問題を解決

Swagger UIだけ通す(permitの最小ルール)

Securityを入れると、Swagger UIがログイン画面に飛ぶ/403になるのが定番です。

まずは「Swagger関連のパスだけ例外」にします(最小でOKです)。

@Bean
SecurityFilterChain security(HttpSecurity http) throws Exception {
  http.authorizeHttpRequests(auth -> auth
      .requestMatchers("/swagger-ui/**", "/swagger-ui.html", "/v3/api-docs/**").permitAll()
      .anyRequest().authenticated()
  );
  return http.build();
}

まずこれで UIが開ける状態 を作ってから、全体の認可ルールを育てるのが安全です。

Bearer(JWT)入力を出す(Authorizeボタン)

「Swagger画面からJWT付きで試したい」なら、OpenAPIにBearer設定を足します。これでUIにAuthorizeボタンが出ます。

@Bean
OpenAPI openAPI() {
  return new OpenAPI()
    .components(new Components().addSecuritySchemes("bearerAuth",
      new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT")))
    .addSecurityItem(new SecurityRequirement().addList("bearerAuth"));
}

※全部に必須を付けたくない場合は、必要なAPIだけ @SecurityRequirement(name="bearerAuth") を付ける運用がラクです。

CSRF・ログイン画面に飛ぶ時の考え方

  • ログイン画面に飛ぶ:だいたい「permit漏れ」です。まずは /v3/api-docs/**/swagger-ui/** を通してください。
  • 403(特にPOST/PUT/DELETE):CSRFが原因のことがあります。開発中は割り切って csrf.disable() もアリですが、最低でも「Swagger関連だけ無視」みたいに範囲を絞るのが無難です。
Postman: The World's Leading API Platform | Sign Up for Free
Accelerate API development with Postman's all-in-one platform. Streamline collaboration and simplify the API lifecycle f...
The Collaborative API Development Platform
Leading Open Source API Development Platform for HTTP, REST, GraphQL, gRPC, SOAP, and WebSockets

本番でSwagger UIを出していい?安全な出し分け

結論:原則「開発だけON」が安心

結論から言うと、Swagger UIは原則「開発環境だけON」が一番安全です。

画面が見える=APIの入口や仕様が分かるので、本番でうっかり公開すると、攻撃のヒントを渡しやすいです。

例外は「社内VPN内だけ」「IP制限済み」「認証もガチガチ」みたいに、外から触れない前提が作れる時ですね。

UIだけOFF/API定義もOFF(どっちを止める?)

  • UIだけOFF:画面は消えるけど、/v3/api-docs は残る(自動生成JSONは取れる)
  • API定義もOFF/v3/api-docs 自体を止める(より強め)

「社内ツールが定義JSONを読む」みたいな事情がなければ、基本は 両方OFF寄りでOKです。

profileで切り替える(dev/prodの例)

application-dev.yml(開発だけON)

springdoc:
  swagger-ui:
    enabled: true
  api-docs:
    enabled: true

application-prod.yml

springdoc:
  swagger-ui:
    enabled: false
  api-docs:
    enabled: false

これで devは見える、prodは見えない がキレイに作れます。

代わりに「定義ファイルを配る」選択肢

本番で画面を出さなくても、OpenAPIのJSON/YAMLを成果物として共有すれば困りません。

たとえばCIで /v3/api-docs を叩いてファイル化→社内Wikiやリポジトリに置く、みたいな運用が堅いです。

安全策のカテゴリ(紹介するなら):社内VPN/リバースプロキシのアクセス制御/WAF・IP制限(サービスにより価格いろいろ)。

よくあるエラー集(症状→原因→直し方)

ここは“救急箱”です。

今出てる症状に近いところだけ見て、そのまま直しに行ってください。

404になる(URL・依存関係・パス競合)

  • 症状/swagger-ui.../v3/api-docs も 404
  • 原因あるある
    • …-ui じゃない依存を入れてる/WebMVCとWebFluxを取り違え
    • context-path を付けてるのにURLに付け忘れ
    • SPAの index.html や静的ファイルが飲み込んでる
  • 直し方
    • springdoc-openapi-starter-*-ui を入れてるか確認
    • /{context}/swagger-ui/index.html/{context}/v3/api-docs で試す
    • Swaggerのパスは無理にいじらず /swagger-ui/ 配下のままにする
  • 確認:まず /v3/api-docs がJSONを返すか(ここが出れば勝ち)

真っ白/定義を読めない(api-docs側の確認)

  • 症状:UIは開くけど真っ白、読み込み失敗っぽい
  • 原因あるある/v3/api-docs が落ちてる(500)/プロキシ配下でURLがズレてる
  • 直し方
    • ブラウザで /v3/api-docs を直で開く(JSONが出なければUI以前の問題)
    • リバースプロキシ配下なら、まず context-path と公開URLの整合を確認
  • 確認/v3/api-docs が200でJSON、UIの更新(リロード)で復活するか

No operations defined(Controller検出・パッケージ)

  • 症状:「No operations defined in spec!」みたいにAPIが0件
  • 原因あるある
    • ControllerがSpringに検出されてない(パッケージがズレてる)
    • @RestController@RequestMapping 付け忘れ
    • 開発中に別モジュールに置いててスキャン外
  • 直し方
    • @SpringBootApplication の位置(ベースパッケージ)とControllerの場所を揃える
    • とりあえず 最小GETを1本作って出るか確認
  • 確認/v3/api-docspaths/hello などが出るか

起動失敗(依存の不一致・バージョン)

  • 症状:起動時に例外で落ちる/クラスが見つからない系
  • 原因あるある:Spring Bootとspringdocの世代ズレ、依存が混ざってる
  • 直し方
    • Boot 3系なら springdoc 2系、Boot 2系なら springdoc 1系に寄せる
    • starter-webmvc-uistarter-webflux-ui を両方入れない(どっちかだけ)
  • 確認:依存を整理→起動→/v3/api-docs が出るか

CORSで叩けない(別ポート・別ドメイン)

  • 症状:Swagger UIから叩くとCORSで失敗(ブラウザの赤いエラー)
  • 原因あるある:UIを開いてる場所とAPIの場所が別(ポート/ドメイン違い)
  • 直し方
    • 開発中は @CrossOrigin で一時対応、もしくはCORS設定を追加
    • 「どこからどこへ通信してるか」を先に確定(例:localhost:3000 → localhost:8080
  • 確認:ブラウザ開発者ツールのNetworkで、リクエストが200/401/403の“普通の結果”になってるか(CORSエラーが消えてるか)

最後のチェックリスト&次の一歩(CTA)

まず合格ライン(新人の提出OK)

提出前に、ここだけチェックすればOKです👇

  • Swagger UIが開く(/swagger-ui/index.html
  • API一覧が見える(最低1本は表示される)
  • どれか1つに 1行説明(@Operation) が入ってる
  • 本番で SwaggerをOFF にできる(profileで切り替え)

この4つできてたら、新人の「まず合格ライン」は超えてます。

チームで育てる改善ロードマップ

次にやるならこの順がラクです。

  • タグで整理して迷子を消す
  • 成功/失敗のレスポンス例を増やす
  • 認証(JWTなど)をSwagger画面から試せるようにする
  • エラー形式をControllerAdviceで完全統一する
  • APIをグループ分けして、画面をさらに見やすくする

参考リンク(公式/互換表/サンプル)

最後に、困ったらここを見れば戻れる、って場所だけ貼っておきます。

  • springdoc-openapi公式ドキュメント(設定・サンプル)
  • Spring Bootとの互換表(バージョン迷子防止)
  • サンプルプロジェクト(動くものを見るのが最速)

よくある質問

Q
SwaggerとOpenAPIって、結局なにが違うんですか?
A

OpenAPIは「APIの説明書の型」で、Swagger UIは「その説明書を見やすく表示する画面」です。
Spring Bootだと、説明書を自動で作ってくれる役が springdoc-openapi です。

Q
Spring BootでSwagger UIを出すには、何を入れればいいですか?
A

基本は springdoc-openapi の “UI付きスターター” を入れればOKです。
「UIなし」を入れると、/v3/api-docs は出ても画面が出ないことがあります。

Q
WebMVCとWebFlux、どっちの依存を選べばいいですか?
A

目安はこれです。

  • spring-boot-starter-web を使ってる → WebMVC
  • spring-boot-starter-webflux を使ってる → WebFlux

混ぜるとハマるので、どっちか1つに寄せてください。

Q
Swagger UIのURLはどれを開けばいいですか?(404になります)
A

まずこの順で試してください。

  • /v3/api-docs(JSONが出るか)
  • /swagger-ui.html
  • /swagger-ui/index.html

最優先は /v3/api-docs が出るかです。ここが出ればだいぶ勝ちです。

Q
/v3/api-docs が404です。何が原因ですか?
A

よくあるのはこの3つです。

  • 依存関係が入ってない/違うスターターを入れてる
  • context-path を設定していて、URLに付け忘れてる
  • アプリがそもそも起動できてない(別のエラーで落ちてる)
Q
UIは開くのに真っ白です。どう直せばいいですか?
A

まず /v3/api-docs をブラウザで直に開いてください。
ここが 500だったり、JSONが返ってないなら、UIの問題じゃなくて「定義を作る側」がコケてます。

Q
「No operations defined」って出ます。なにそれですか?
A

「APIが0件」扱いになってます。原因はだいたいこれです。

  • ControllerがSpringに見つかってない(パッケージ位置がズレてる)
  • @RestController@GetMapping を付け忘れ

最小のGETを1本作って、出るか確認すると早いです。

Q
Spring Security入れたらSwaggerが見れません(ログイン画面/403)
A

あるあるです。Swagger関連のパスだけ通す(permit)のが最短です。
通す候補はこのへん:

  • /swagger-ui/**
  • /swagger-ui.html
  • /v3/api-docs/**

まずUIを開ける状態を作ってから、認可を固めるのが安全です。

Q
Swagger UIに「Authorize(JWT入力)」を出したいです
A

OpenAPI側に Bearer認証の設定を足すと出せます。
すると画面からトークンを入れて、そのままAPIを試せるようになります。
「全部に必須」じゃなくて、必要なAPIだけ必須にする運用もできます。

Q
本番でSwagger UIを出してもいいですか?
A

原則は 本番はOFF が安心です。
どうしても出すなら、社内VPN内・IP制限・認証強めみたいに「外から触れない前提」を作るのが基本です。
運用としては profileで devはON / prodはOFF が一番ラクです。

タイトルとURLをコピーしました