【実務・中級編】Spring Boot開発でSwagger/OpenAPI (Springdoc OpenAPI) を導入する方法 – データベース・API管理活用バイブル

Spring Boot 3系におけるSwagger/OpenAPI導入の極意:開発スピードを極限まで高める実践アーキテクチャ

テックリードの私たちが常に直面する課題、それは「実装とドキュメントの乖離」だ。
古いWiki、メンテナンスされないExcelのAPI仕様書、そして「コードを見ればわかる」というエンジニアの怠惰な免罪符。これらはチームの生産性を静かに、しかし確実に蝕んでいく。

Spring Boot 3系(Jakarta EEベース)でのAPI開発において、この悪夢を断ち切る唯一にして最強の解が `springdoc-openapi` だ。単に「Swagger UIを表示させるだけ」の導入で満足していないか?

本記事では、単なる導入手順にとどまらず、開発スピードを劇的にブーストさせる設定のベストプラクティス、現場で即座に使えるアノテーション戦略、そしてチーム開発を円滑にするための実践的な知見を、容赦なくコードベースで解説する。

—

1. 依存関係の追加:Spring Boot 3系における最適解

まずは `build.gradle` の設定からだ。Spring Boot 3系(Spring Framework 6 / Jakarta EE 9以降)では、旧 `springfox` は完全に死亡している。選択すべきは `springdoc-openapi-starter-webmvc-ui` の一択だ。

`build.gradle` (Groovy DSL) のベストプラクティス

余計な推移的依存関係を持ち込まず、バージョン管理を一元化するための記述がこれだ。

plugins {
id ‘org.springframework.boot’ version ‘3.2.x’
id ‘io.spring.dependency-management’ version ‘1.1.4’
id ‘java’
}

group = ‘com.example’
version = ‘1.0.0’
java {
sourceCompatibility = ’17’ // Spring Boot 3の最低要件
}

repositories {
mavenCentral()
}

dependencies {
// Spring Boot WebMVC スターター
implementation ‘org.springframework.boot:spring-boot-starter-web’

// Bean Validation (OpenAPIのアノテーションと連携するため必須級)
implementation ‘org.springframework.boot:spring-boot-starter-validation’

// 【最重要】Springdoc OpenAPI UI (Spring Boot 3系対応)
// これ一つで Swagger UI, OpenAPI JSON/YAML エンドポイントがすべて有効化される
implementation ‘org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0’

// Lombok (ボイラープレートコード削減の必須ツール)
compileOnly ‘org.projectlombok:lombok’
annotationProcessor ‘org.projectlombok:lombok’

// テスト用
testImplementation ‘org.springframework.boot:spring-boot-starter-test’
}

> 💡 プロの知見:
> 意外と見落としがちなのが `spring-boot-starter-validation` だ。これを導入しておくと、`@NotNull` や `@Size` などのJakarta ValidationアノテーションをSpringdocが自動解釈し、OpenAPIのスキーマ定義(`required` や `maxLength`)へシームレスに反映してくれる。二重定義の地獄から解放される最初のステップだ。

—

2. 現場で生き残る `application.yml` 設定の極意

デフォルトのまま動かしている開発チームは、セキュリティリスクを抱えるか、あるいはフロントエンドチームからの「使いにくい」というクレームに悩まされることになる。
本番環境での露出制御、パスのカスタマイズ、UIの挙動チューニングを網羅した、実戦投入済みの `application.yml` を提示する。

`src/main/resources/application.yml`

spring:
application:
name: “Enterprise Core API”

Springdoc OpenAPI 専用設定
springdoc:
# Swagger UI のパスを変更(デフォルトは /swagger-ui.html)
# セキュリティ上の理由から推測されにくいパスに偽装するか、/api/docs/swagger-ui.html などに寄せる
swagger-ui:
path: /swagger-ui.html
# タグのソート順: alpha (アルファベット順), method (HTTPメソッド順), カスタム定義
tags-sorter: alpha
# オペレーションのソート順
operations-sorter: method
# リクエストのTry it outで、モデルのサンプルをデフォルト展開するか
display-request-duration: true
# 「Try it out」ボタンをデフォルトで有効化
filter: true
# 認証情報をブラウザのLocalStorageに保持するか(リロード対策)
persist-authorization: true

# OpenAPIドキュメント(JSON/YAML)の出力パス
api-docs:
path: /v3/api-docs
enabled: true

# スキャン対象パッケージの絞り込み(パフォーマンス向上と不要なフレームワーク内エンドポイントの除外)
packages-to-scan: com.example.core.presentation.controller

# デフォルトレスポンスのグローバル設定などを防ぎ、正確なスキーマを生成する
default-produces-media-type: application/json
default-consumes-media-type: application/json

プロファイル別の制御(本番環境ではSwaggerを完全無効化することを強く推奨)
—
spring:
config:
activate:
on-profile: prod
springdoc:
api-docs:
enabled: false
swagger-ui:
enabled: false

—

3. アノテーション駆動設計:プロダクション品質のAPIドキュメント構築

ここからが本番だ。自動生成されたドキュメントは「動くが、不親切」なことが多い。
優れたテックリードは、アノテーションを戦略的に配置し、フロントエンドエンジニアや外部連携パートナーが迷わないドキュメントをコードファーストで構築する。

実例として、「ユーザー登録API」のコントローラーとリクエストDTOを実装する。

リクエストDTO (`UserRegisterRequest.java`)

Bean Validation と OpenAPI アノテーションの融合を見よ。

package com.example.core.presentation.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Data;

@Data
@Schema(description = “ユーザー登録リクエストDTO”)
public class UserRegisterRequest {

@NotBlank(message = “ユーザー名は必須です”)
@Size(min = 3, max = 50, message = “ユーザー名は3文字以上50文字以下で指定してください”)
@Schema(description = “ユーザーアカウント名”, example = “john_doe_99”, requiredMode = Schema.RequiredMode.REQUIRED)
private String username;

@NotBlank(message = “メールアドレスは必須です”)
@Email(message = “有効なメールアドレス形式である必要があります”)
@Schema(description = “連絡先メールアドレス”, example = “john.doe@example.com”, requiredMode = Schema.RequiredMode.REQUIRED)
private String email;

@NotBlank(message = “パスワードは必須です”)
@Size(min = 8, max = 100, message = “パスワードは8文字以上で指定してください”)
@Schema(description = “ログインパスワード(平文。TLSで保護されます)”, example = “P@ssw0rd!Secure”, requiredMode = Schema.RequiredMode.REQUIRED)
private String password;
}

コントローラー (`UserController.java`)

`@Tag`, `@Operation`, `@ApiResponses` を駆使し、ビジネス文脈を完全にコードに閉じ込める。

package com.example.core.presentation.controller;

import com.example.core.presentation.dto.UserRegisterRequest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.;

@RestController
@RequestMapping(“/api/v1/users”)
@Tag(name = “User Management”, description = “ユーザーの登録、参照、管理を行うエンドポイント群”)
public class UserController {

@PostMapping
@Operation(
summary = “新規ユーザー登録”,
description = “指定された情報をもとに新規ユーザーアカウントを作成します。登録成功後、アクティベーションメールが送信されます。”
)
@ApiResponses(value = {
@ApiResponse(
responseCode = “201”,
description = “ユーザー登録成功”,
content = @Content(mediaType = “application/json”, schema = @Schema(implementation = UserRegisterRequest.class))
),
@ApiResponse(
responseCode = “400”,
description = “バリデーションエラー(入力値不正)”,
content = @Content
),
@ApiResponse(
responseCode = “409”,
description = “競合エラー(すでに存在するメールアドレス)”,
content = @Content
)
})
public ResponseEntity registerUser(
@Parameter(description = “ユーザー登録情報”, required = true)
@RequestBody @Valid UserRegisterRequest request) {

// ── ビジネスロジックの呼び出し(省略) ──

// 201 Created を返却
return ResponseEntity.status(HttpStatus.CREATED).build();
}
}

—

4. チーム開発の生産性を爆発させる「プロの隠し技」

ここからは、一般的なチュートリアルでは語られない、現場のテックリードが仕込むべき「真の生産性向上ハック」を伝授する。

① グローバルセキュリティ定義のJava設定 (`OpenApiConfig.java`)

JWT認証やOAuth2を使っている場合、すべてのエンドポイントに手動でBearerトークンの設定をするのは狂気の沙汰だ。JavaのコンフィグでグローバルにJWT認証スキームを定義し、Swagger UI右上の「Authorize」ボタン一つで全APIに適用させよ。

package com.example.core.config;

import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class OpenApiConfig {

@Bean
public OpenAPI customOpenAPI() {
final String securitySchemeName = “bearerAuth”;

return new OpenAPI()
.info(new Info()
.title(“Enterprise Core API Specification”)
.version(“v1.0.0”)
.description(“次世代基幹システム向けRESTful APIの公式仕様書です。”)
.contact(new Contact()
.name(“Core Platform Team”)
.email(“platform-team@example.com”))
.license(new License()
.name(“Proprietary”)
.url(“https://example.com/terms”)))
// グローバルセキュリティ要件の追加
.addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
.components(new Components()
.addSecuritySchemes(securitySchemeName,
new SecurityScheme()
.name(securitySchemeName)
.type(SecurityScheme.Type.HTTP)
.scheme(“bearer”)
.bearerFormat(“JWT”)
.description(“JWTアクセストークンを入力してください(例: Bearer eyJhbGciOi…)”)));
}
}

② CI/CDパイプラインへの組み込み:API仕様書の静的吐き出し

フロントエンドチームやQAエンジニアに「最新のAPI仕様書をくれ」と言われたら、アプリを起動させてJSONをコピペさせているのか? それは前時代的だ。
Gradleタスクを使って、ビルド時に自動でOpenAPIのJSONをファイルとして出力し、Gitで管理するかArtifactsとして保存する仕組みを作れ。

Spring Bootが起動している状態でエンドポイントを叩くテストを利用するか、あるいは以下のテストクラスを書いてCI(GitHub Actionsなど)で実行時に `openapi.json` をアーティファクトとして吐き出す。

package com.example.core;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@AutoConfigureMockMvc
class GenerateOpenApiDocsTest {

@Autowired
private MockMvc mockMvc;

@Test
void generateOpenApiJson() throws Exception {
// v3/api-docs にアクセスして JSON を取得し、build/docs ディレクトリに保存する
byte[] content = mockMvc.perform(get(“/v3/api-docs”))
.andExpect(status().isOk())
.andReturn()
.getResponse()
.getContentAsByteArray();

Path outputPath = Path.of(“build/docs/openapi.json”);
Files.createDirectories(outputPath.getParent());
Files.write(outputPath, content, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
}
}

このテストを `./gradlew test` のライフサイクルに組み込むだけで、常に最新のAPI仕様書ファイルがコードベースと共にビルド成果物として生成されるようになる。これをOpenAPI Generatorと組み合わせれば、フロントエンドのTypeScript型定義の自動生成(APIクライアントの完全自動化)への道が拓ける。

—

結び:ドキュメント駆動開発(DDD)へのパラダイムシフト

Springdoc OpenAPIの導入は、単なる「便利なUIツールを入れる作業」ではない。
コードとドキュメントの主従関係を正し、「実装がそのまま正確な仕様書になる」という開発者フレンドリーなエコシステムをチームにもたらすための重要な布石である。

ここに示した設定とアノテーション戦略、そしてCI連携の知見をそのままプロジェクトに適用してほしい。会議室で「今のAPIの仕様はどうなっているんだっけ?」と議論する無駄な時間は、今日で終わりにするべきだ。

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