swaggerを使用してAPIの仕様をドキュメントかしていると、swaggerのメンテナンスがされなくなり実装とドキュメントがドンドンずれていく、、、なんてこと良くありますよね。。
そんなときコードベースでswaggerを自動生成してくれるspringfox
を見つけました!
この記事では、できるだけswagger.yamlを手動で書いた時と同じクオリティになるようspringfox
の使い方をまとめていきます!
▼メンテされているライブラリを使いたい場合はこちらをご覧ください
【逆引き解説】SpringDocの使い方前提
ライブラリ | バージョン |
---|---|
org.springframework.boot:spring-boot-starter-web | 2.4.0 |
org.springframework.boot:spring-boot-starter-validation | 2.4.0 |
io.springfox:springfox-boot-starter | 3.0.0 |
サンプルAPI
なんとなくユーザーを登録するエンドポイントとユーザーを検索するエンドポイントを用意しました
@RestController
@Validated
public class SampleController {
@PostMapping(value = "/sample",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public void register(@RequestBody @Valid User request) {
return;
}
@GetMapping(value = "/sample", produces = MediaType.APPLICATION_JSON_VALUE)
public User get(@Pattern(regexp = "[0-9a-f-]{36}") String id) {
return new User("1234567890", "hogehoge", 30);
}
@Value
public static class User {
@NotNull
@Pattern(regexp = "[0-9a-f-]{36}")
private String id;
@NotNull
private String name;
@NotNull
@Min(1L)
@Max(100L)
private int age;
}
}
springfox導入
導入はライブラリを入れてConfigurationクラスを実装するだけ!
dependencies {
...
// springfoxの依存を追加する
implementation 'io.springfox:springfox-boot-starter:3.0.0'
}
@Configuration
@EnableSwagger2
public class SwaggerAutoConfiguration {
}
アプリケーションを起動して、
http://localhost:8080/swagger-ui/
にアクセスするとSwaggerが表示されます!
これだけでも結構いい感じですね!
ちなみにValidationも反映してくれてます😍
※このあともう少しリッチにできます
詳細な設定
ここからは設定を追加して。swaggerを充実させていきます。
トップページの設定
ある程度まとめて設定を入れてみます
@Configuration
@EnableSwagger2
public class SwaggerAutoConfiguration {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("<package>"))
.paths(PathSelectors.any())
.build()
// 200以外でデフォルトで用意されているレスポンスを無効にします
.useDefaultResponseMessages(false)
// プロトコルを指定します
.protocols(Collections.singleton("https"))
.apiInfo(new ApiInfo(
// タイトル
"springfoxサンプル",
// 説明
"springfoxのサンプル",
// ドキュメントのバージョン
"1.0.0",
null,
null,
null,
null,
Collections.emptyList()
));
}
}
これで情報がすっきりしました!
バリデーションも少し表現が増えています
APIのタイトル
デフォルトだと「sample-controller」と、コントローラーのクラス名が使われているのでこれを変更してみる
→ @Api
アノテーションでtags
を指定すればOK
@Api(tags = "サンプルAPI")
@RestController
@Validated
public class SampleController {
...
}
エンドポイントの説明を変える
デフォルトだとControllerクラスのメソッド名が使われていそうなのでこれを変更してみる
→ @ApiOperation
アノテーションでvalue
を指定すればOK
...
@ApiOperation("ユーザー登録")
@PostMapping(value = "/register",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public void register(@RequestBody @Valid User request) {
return;
}
@ApiOperation("ユーザー検索")
@GetMapping(value = "/get", produces = MediaType.APPLICATION_JSON_VALUE)
public User get(@Pattern(regexp = "[0-9a-f-]{36}") String id) {
return new User("1234567890", "hogehoge", 30L);
}
...
Modelに説明やサンプルを追加する
Modelクラスの各フィールドに@ApiModelProperty
を付与します
- value: 説明
- required: 必須かどうか
- デフォルトがfalseとなっていて
@NotNull
よりも優先されてしまうので明示的に指定が必要
- position: 表示順序
- ageの位置がおかしい😇
- example: 値のサンプル
@Value
public static class User {
@ApiModelProperty(value = "ID", required = true, position = 1,
example = "8cdd25ef-b8e4-4964-ab78-2ef5e16b54be")
@NotNull
@Pattern(regexp = "[0-9a-f-]{36}")
private String id;
@ApiModelProperty(value = "名前", required = true, position = 2,
example = "hogehoge")
@NotNull
private String name;
@ApiModelProperty(value = "年齢", required = true, position = 2,
example = "30")
@NotNull
@Min(1)
@Max(100)
private int age;
}
共通のエラーレスポンスを追加する
作成したSwaggerAutoConfiguration
に追記します。
.apiInfo(...)
.globalResponses(HttpMethod.POST, Arrays.asList(
new ResponseBuilder()
.code("400")
.description("Bad Request")
.build()));
ボディは指定できない…かな😇
エンドポイントごとのエラーレスポンスを追加する
@ApiResponses
と@ApiResponse
を使用します
- code: レスポンスコード
- message: エラーの概要
- response: レスポンスのModelクラス
@ApiOperation("ユーザー登録")
@PostMapping(value = "/register",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "成功", response = Void.class),
@ApiResponse(code = 500, message = "システムエラー", response = ErrorResource.class)
})
public void register(@RequestBody @Valid User user) {
return;
}
クエリパラメータに説明やサンプルを追加する
@ApiParam
アノテーションを使用します
- name: パラメータ名
- 指定しないと引数の名前をそのまま使ってくれるので、出番ないかも?
- value: 説明
- required: 必須かどうか
- example: 例
@ApiOperation("ユーザー検索")
@GetMapping(value = "/get", produces = MediaType.APPLICATION_JSON_VALUE)
public User get(
@ApiParam(value = "ユーザーのID", required = true, example = "8cdd25ef-b8e4-4964-ab78-2ef5e16b54be")
@Pattern(regexp = "[0-9a-f-]{36}") String id) {
return new User("1234567890", "hogehoge", 30);
}