かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

springdoc-openapi メモ書き

概要

記事一覧はこちらです。

springdoc-openapi を試した時のメモ書きです。

参照したサイト・書籍

  1. Documenting Spring Boot Rest API With OpenAPI 3.0
    https://tebatso191.medium.com/documenting-spring-boot-rest-api-with-openapi-3-0-a49be5e836ad

  2. springdoc-openapi
    https://springdoc.org/

  3. Springdoc-openapi Demos
    https://springdoc.org/#demos

  4. springdoc / springdoc-openapi-demos
    https://github.com/springdoc/springdoc-openapi-demos

  5. OpenAPI Specification
    https://swagger.io/specification/

  6. API Documentation & Design Tools for Teams | Swagger
    https://swagger.io/

  7. springdoc / springdoc-openapi-gradle-plugin
    https://github.com/springdoc/springdoc-openapi-gradle-plugin

  8. OpenAPI (Swagger) 超入門
    https://qiita.com/teinen_qiita/items/e440ca7b1b52ec918f1b

  9. Swagger(OAS) 3.0の登場
    https://news.mynavi.jp/itsearch/article/devsoft/3854

  10. Swagger ではない OpenAPI Specification 3.0 による API サーバー開発
    https://www.slideshare.net/techblogyahoo/swagger-openapi-specification-30-api

目次

  1. WebAPI を提供する Web アプリを作成する
  2. springdoc-openapi-ui を依存関係に追加し、application.properties に設定を追加する
  3. @SpringBootApplication 付与クラスに @OpenAPIDefinition アノテーションを付与して API の情報を表示する
  4. @RestController 付与クラスに @Tag、@Operation、@ApiResponses 等のアノテーションを付与して REST API の情報を表示する
  5. @RestControllerAdvice 付与クラスの @ExceptionHandler を付与したメソッドが UI に表示されないようにする
  6. POJO クラスに @Schema アノテーションを付与して UI の Schemas に表示される情報を追加する
  7. Swagger Petstore のページが表示されないようにする
  8. /api-docs にアクセスすると JSON の、/api-docs.yaml にアクセスすると YAML の OpenAPI ドキュメントがダウンロードできる
  9. 最後に

手順

WebAPI を提供する Web アプリを作成する

Web アプリを作成して ksbysample-springdoc-openapi-sample に入れます。

springdoc-openapi-ui を依存関係に追加し、application.properties に設定を追加する

まず build.gradle を変更します。

dependencies {
    ..........

    // dependency-management-plugin によりバージョン番号が自動で設定されないもの、あるいは最新バージョンを指定したいもの
    implementation("org.springdoc:springdoc-openapi-ui:1.5.5")
    testImplementation("net.javacrumbs.json-unit:json-unit-spring:2.25.0")

    ..........
  • implementation("org.springdoc:springdoc-openapi-ui:1.5.5") を追加します。

src/main/resources/application.properties を以下のように変更します。

server.port=9080

springdoc.api-docs.path=/api-docs
springdoc.swagger-ui.path=/swagger-ui.html
  • 以下の2行を追加します。springdoc.swagger-ui.path の方は default 値と同じ設定なので記述しなくてもよいのですが、書いておいた方が URL を思い出しやすいかなと思い明記しています。springdoc.api-docs.path も default の /v3/api-docs のままでよければ書く必要はありません。
    • springdoc.api-docs.path=/api-docs
    • springdoc.swagger-ui.path=/swagger-ui.html
  • server.port=9080 を設定しているのは default の 8080 以外の場合の動作を確認するためです(実際には何もすることはありませんでした)。

Web アプリを起動して http://localhost:9080/swagger-ui.html にアクセスすると以下の画面が表示されます。タイトルが OpenAPI definition で、バージョンが v0、その下の endpoint や Schemas には何も説明がついていない状態です。

f:id:ksby:20210319010036p:plain

@SpringBootApplication 付与クラスに @OpenAPIDefinition アノテーションを付与して API の情報を表示する

src/main/java/ksbysample/webapp/springdocsample/SpringdocSampleApplication.java に @OpenAPIDefinition アノテーションを付与します。

package ksbysample.webapp.springdocsample;

import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Info;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@OpenAPIDefinition(info = @Info(title = "ksbysample-springdoc-openapi-sample",  // (1)
        description = "Spring Boot + springdoc-openapi のサンプルアプリ",  // (2)
        version = "v1"))  // (3)
public class SpringdocSampleApplication {

    ..........

@OpenAPIDefinition アノテーションの各属性の記述は UI の以下の場所に表示されます。

f:id:ksby:20210324222448p:plain

@RestController 付与クラスに @Tag、@Operation、@ApiResponses 等のアノテーションを付与して REST API の情報を表示する

src/main/java/ksbysample/webapp/springdocsample/webapi/book/WebapiBookController.java に @Tag、@Operation、@ApiResponses 等のアノテーションを付与します。

package ksbysample.webapp.springdocsample.webapi.book;

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 ksbysample.webapp.springdocsample.exception.BookInvalidException;
import ksbysample.webapp.springdocsample.exception.BookNotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RestController
@RequestMapping("/webapi/book")
@Tag(name = "Book", description = "the Book API")
public class WebapiBookController {

    ..........

    @Operation(summary = "Book データを登録する",
            description = "Book データを受け取ってリストに追加する")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功"),
            @ApiResponse(responseCode = "405", description = "入力チェックエラー")
    })
    @PostMapping
    public void add(
            @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "Book データ")
            @Validated @RequestBody Book book,
            BindingResult bindingResult) {
        ..........
    }

    @Operation(summary = "Book データを検索する",
            description = "指定された ISBN の Book データを検索する")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功",
                    content = @Content(mediaType = "application/json", schema = @Schema(implementation = Book.class))),
            @ApiResponse(responseCode = "404", description = "指定された ISBN の Book データが存在しない",
                    content = @Content)
    })
    @GetMapping("/{isbn}")
    public Book findByIsbn(
            @Parameter(required = true, description = "ISBN-13", example = "978-4873119038")
            @PathVariable String isbn) {
        ..........
    }

}

API が以下のように表示されます。

f:id:ksby:20210324225506p:plain

/webapi/book API は以下のように表示されます。Response に @ApiResponses に記述していない 404 が表示されていますが、これは @RestControllerAdvice クラスに定義したものが表示されているからです。この後に表示されないように記述を追加します。

f:id:ksby:20210324225636p:plain f:id:ksby:20210324225724p:plain

Request body の Book データの Schema タブをクリックすると以下の表示に切り替わります。

f:id:ksby:20210324225857p:plain

/webapi/book/{isbn} API は以下のように表示されます。こちらは不要な 405 が表示されています。

f:id:ksby:20210324225955p:plain f:id:ksby:20210324230102p:plain

@RestControllerAdvice 付与クラスの @ExceptionHandler を付与したメソッドが UI に表示されないようにする

@RestControllerAdvice 付与クラスの @ExceptionHandler を付与したメソッドの情報が各 API の Responses に表示されますが、今回は不要なので class に @Hide アノテーションを付与して表示されないようにします。

package ksbysample.webapp.springdocsample.webapi.book;

import io.swagger.v3.oas.annotations.Hidden;
import ksbysample.webapp.springdocsample.exception.BookInvalidException;
import ksbysample.webapp.springdocsample.exception.BookNotFoundException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * WebAPI 用 Error Handler クラス
 */
@RestControllerAdvice
@Hidden
public class WebapiBookErrorHandler {

    ..........

API の Responses の表示が以下のようになります。

f:id:ksby:20210324232112p:plain f:id:ksby:20210324232213p:plain

POJO クラスに @Schema アノテーションを付与して UI の Schemas に表示される情報を追加する

src/main/java/ksbysample/webapp/springdocsample/webapi/book/Book.java に @Schema アノテーションを付与します。

package ksbysample.webapp.springdocsample.webapi.book;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDate;

/**
 * Book データクラス
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString
@Schema(description = "Book データ")
public class Book {

    @NotBlank
    @Schema(type = "string", required = true, description = "ISBN-13", example = "123-1234567890")
    private String isbn;

    @NotBlank
    @Schema(type = "string", required = true, description = "書籍名",
            example = "サンプル本")
    private String name;

    @NotNull
    @Schema(type = "number", required = true, description = "価格", example = "3600")
    private BigDecimal price;

    @Schema(type = "string", format="date", required = true, description = "発売日", example = "2021-03-24")
    private LocalDate releaseDate;

}

UI の Schemas に以下のように表示されます。

f:id:ksby:20210324234045p:plain

Swagger Petstore のページが表示されないようにする

UI が表示されているブラウザのアドレスバーの URL http://localhost:9080/swagger-ui/index.html?configUrl=/api-docs/swagger-config から ?configUrl=/api-docs/swagger-config を取り除くと Swagger Petstore の情報が表示されます。

f:id:ksby:20210324235856p:plain

表示させたくない場合、application.properties に springdoc.swagger-ui.disable-swagger-default-url=true を追加します。

server.port=9080

springdoc.api-docs.path=/api-docs
springdoc.swagger-ui.disable-swagger-default-url=true
springdoc.swagger-ui.path=/swagger-ui.html

f:id:ksby:20210325000644p:plain

/api-docs にアクセスすると JSON の、/api-docs.yaml にアクセスすると YAML の OpenAPI ドキュメントがダウンロードできる

http://localhost:9080/api-docs にアクセスすると JSON の OpenAPI ドキュメントが表示され、

f:id:ksby:20210325002440p:plain

http://localhost:9080/api-docs.yaml にアクセスすると YAML の OpenAPI ドキュメントがダウンロードできます。

f:id:ksby:20210325002623p:plain

最後に

他にも以下のようなことができる(らしい)。テストは試してみましたが、下の2つは記事を見かけただけです。

今回の変更内容はこちらです。
https://github.com/ksby/ksbysample-springdoc-openapi-sample/compare/before...after

履歴

2021/03/25
初版発行。 2021/03/27
* 最後に に今回変更した点が分かるリンクを追加しました。