springdoc で API ドキュメント作成
API 設計書の作成方法について説明します。springdoc-openapi によって swagger を自動生成するようにしています。
実装
pom.xml
下記の依存関係を追加します:
<!-- https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-starter-webmvc-ui -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.8.13</version>
</dependency>
application.properties
下記設定を追記します:
# swagger出力用ymlファイルのエンドポイント
springdoc.api-docs.path=/api-docs
# swaggerドキュメント閲覧用エンドポイント
springdoc.swagger-ui.path=/swagger-ui.html
# application-swagger.ymlを読み込ませる
spring.profiles.active=swagger
EasyappApplication.java
下記アノテーションを追記し、API の概要を記載します:
package nob.example.easyapp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+ import io.swagger.v3.oas.annotations.OpenAPIDefinition;
+ import io.swagger.v3.oas.annotations.info.Info;
@SpringBootApplication
+ @OpenAPIDefinition(info = @Info(title = "Easy App", version = "1.0.0", description = "サンプルのREST APIです。"))
public class EasyappApplication {
public static void main(String[] args) {
SpringApplication.run(EasyappApplication.class, args);
}
}
AuthController.java
下記アノテーションを追記し、各 API のインターフェース仕様を記載します:
package nob.example.easyapp.controller;
+ import org.springdoc.core.annotations.ParameterObject;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
+ import io.swagger.v3.oas.annotations.Operation;
+ 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 nob.example.easyapp.controller.model.LoginRequest;
import nob.example.easyapp.controller.model.LoginResponse;
import nob.example.easyapp.controller.model.MeRequest;
import nob.example.easyapp.controller.model.MeResponse;
import nob.example.easyapp.exception.SampleException;
+ import nob.example.easyapp.handler.SampleExceptionHandler.SampleExceptionResponseBody;
/**
* 認証コントローラーのインターフェースです。
*
* @author nob
*/
@RestController
@RequestMapping(value = "/api/v1")
+ @Tag(name = "Auth", description = "認証APIです。")
public interface AuthController {
/**
* 認証処理を呼び出します。
*
* @param request 認証リクエスト
* @return 認証結果
*/
@PostMapping(value = "/login")
+ @Operation(summary = "認証", description = "${easyappdoc.describe.api.v1.login:説明文}")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "正常に処理された場合"),
+ @ApiResponse(responseCode = "422", description = "エラーが発生した場合", content = @Content(schema = @Schema(implementation = SampleExceptionResponseBody.class)))
+ })
LoginResponse login(@RequestBody LoginRequest request) throws SampleException;
/**
* ユーザ情報取得処理を呼び出します。
*
* @param request ユーザ情報取得リクエスト
* @return ユーザ情報
*/
@GetMapping(value = "/me")
+ @Operation(summary = "ユーザ情報取得", description = "${easyappdoc.describe.api.v1.me:説明文}")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "正常に処理された場合")
+ })
- MeResponse me(MeRequest request);
+ MeResponse me(@ParameterObject MeRequest request);
}
model
各モデルクラスのスキーマ定義を記載します:
LoginRequest.java
package nob.example.easyapp.controller.model;
+ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Value;
/**
* 認証向けのリクエストモデルです。
*
* @author nob
*/
@Value
+ @Schema(description = "認証向けのリクエストモデル", type = "object")
public class LoginRequest {
/** ユーザ名 */
+ @Schema(description = "ユーザ名", type = "string", example = "nob")
private String name;
/** パスワード */
+ @Schema(description = "パスワード", type = "string", example = "passwd")
private String password;
}
LoginResponse.java
package nob.example.easyapp.controller.model;
+ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Value;
/**
* 認証向けのレスポンスモデルです。
*
* @author nob
*/
@Value
+ @Schema(description = "認証向けのレスポンスモデル", type = "object")
public class LoginResponse {
/** 認証可否 */
+ @Schema(description = "認証可否", type = "boolean", example = "true")
private boolean valid;
}
MeRequest.java
package nob.example.easyapp.controller.model;
+ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Value;
/**
* ユーザ情報取得向けのリクエストモデルです。
*
* @author nob
*/
@Value
+ @Schema(description = "ユーザ情報取得向けのリクエストモデル", type = "object")
public class MeRequest {
/** ユーザ名 */
+ @Schema(description = "ユーザ名", type = "string", example = "nob")
private String name;
}
MeResponse.java
package nob.example.easyapp.controller.model;
+ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Value;
/**
* ユーザ情報取得向けのレスポンスモデルです。
*
* @author nob
*/
@Value
+ @Schema(description = "ユーザ情報取得向けのレスポンスモデル", type = "object")
public class MeResponse {
/** ユーザ名 */
+ @Schema(description = "ユーザ名", type = "string", example = "nob")
private String name;
/** 年齢 */
+ @Schema(description = "年齢", type = "integer", example = "13")
private Integer age;
}
SampleExceptionHandler.java
例外発生時レスポンスモデルのスキーマ定義を記載します:
package nob.example.easyapp.handler;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
+ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Value;
import nob.example.easyapp.exception.SampleException;
/**
* サンプル例外のハンドラです。
*
* @author nob
*/
@RestControllerAdvice
public class SampleExceptionHandler {
/**
* サンプル例外が投げられた際のハンドリングを行います。
*
* @param e
* @return 例外メッセージ
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
@ExceptionHandler(SampleException.class) // SampleExceptionが投げられた際に動く
public ResponseEntity<SampleExceptionResponseBody> handleSampleException(SampleException e) {
return new ResponseEntity(new SampleExceptionResponseBody(e.getMessage()), HttpStatus.UNPROCESSABLE_ENTITY);
}
/**
* サンプル例外発生時のレスポンスボディです。
*/
@Value
+ @Schema(description = "サンプルエラーのレスポンス", type = "object")
public class SampleExceptionResponseBody {
/** エラーメッセージ */
+ @Schema(description = "エラーメッセージ", type = "string", example = "業務エラーが発生しました。")
private String message;
}
}
resources/application-swagger.yaml
API の description について記載します:
########################
### Easy App documents
########################
easyappdoc:
describe:
api:
v1:
login: |
認証処理を行います。リクエストに不備があった場合はエラーレスポンスを返します。
me: |
ユーザ情報を取得します。
動作確認
アプリ起動後、http://localhost:8080/swagger-ui/index.html で swagger ドキュメントを確認できます。
Tips
Try it out ボタンを無効化したい場合
application.properties に下記を追加すればボタンが非表示になります:
springdoc.swagger-ui.supported-submit-methods=[]