SpringdocでAPIの情報を補足する際、リクエストパラメータには@Parameterを使うべきという話

こんにちは、エキサイト株式会社の平石です。

今回は、SpringdocでAPIのリクエストに対して、付与するアノテーションをご紹介します。

なお、今回のソースコードは以下の環境で動作確認をしています。

  • 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'
  • Java 21
  • SpringBoot 3.2.2

はじめに

SpringdocはOpenAPI仕様のAPIドキュメントを自動で生成してくれるライブラリです。
ドキュメントを書く手間も省けますし、Swagger UIを利用すればAPIの動作確認もできるので、事業部でも積極的に活用しています。
Springdocでは、Controllerを記述するだけで最低限のドキュメントを作成してくるのですが、ライブラリで提供される専用のアノテーションを付与することで、情報を補足することもできます。
特に、Controllerを書くだけでは「どのような動作をするAPIなのかの説明」「それぞれのパラメータやレスポンスの詳細な説明」といった情報は表示されませんので、アノテーションを利用して補足する必要があります。

例えば、以下のようなControllerを作成したとします。

@RestController
@RequestMapping("sample")
@Tag(name = "sample")
public class SampleController {
    @GetMapping
    @Operation(summary = "サンプルのAPI")
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "201",
                    description = "正常に処理が終了した場合"
            ),
            @ApiResponse(
                    responseCode = "500",
                    description = "API内部でエラーが発生した場合"
            )
    })
    public String sample() {
        return "Hello, Excite";
    }
}

この時、Swagger UIを確認すると以下のように反映されています。

サンプルのAPI正常に処理が終了した場合といった文言はアノテーションで補足しないと反映されない内容です。

@Schemaを乱用して発生した問題

これまで、私の所属するチームではSpringdocでAPIの情報を補足する際に、リクエストにもレスポンスにも@Schemaのみを付与していました。

@SchemaはOpenAPI仕様上でデータモデルを定義するために使われるアノテーションです。
データモデルと言いつつも、単一のフィールドやパラメータを表現するのにも使用することができます。

しかし、@Schema単体ではリクエストの際に適切に型が反映されないという問題がありました。

例えば、以下のようなControllerを考えます。

@RestController
@RequestMapping("sample")
@Tag("sample")
public class SampleController {
    @GetMapping
    public String sample(
            @ParameterObject SampleRequestDto requestDto
    ) {
        return "Hello, Excite!";
    }
}

SampleResponseDtoには、これから様々なフィールドを記述していきます。

リクエストの場合

APIのリクエストは、Controller内のメソッドの引数にStringIntegerの状態で直接渡すこともできますし、全てのパラメータをまとめたDTOを渡すこともできます。

今回は、DTOを作成してみます。
Javaのレコード・クラスを利用すると便利です。

public record SampleRequestDto(
        String stringField,
        Integer integerField,
        Long longField
) {
}

この状態でSwagger UIを確認してみます。

各パラメータが認識され、型もJava側で宣言した型からOpenAPI仕様で定義されている型に自動で変換してくれています。

ちなみに、()内に$マークと一緒に記述されているint32date-timeformatです。
integer($int64)integerというtype(型)の$int64というフォーマットであることを表しています。
int64はLong型のことなので、Javaの型がOpenAPI仕様で利用できる適切な型(+ フォーマット)に自動的に変換されていることがわかります。

では、リクエストに、descriptionexampleを記述して情報を補足してみます。

public record SampleRequestDto(
        @Schema(description = "文字列のパラメータ", example = "文字列")
        String stringField,
        @Schema(description = "Integer型のパラメータ",  example = "1")
        Integer integerField,
        @Schema(description = "Long型のパラメータ", example = "2")
        Long longField
) {
}

Swagger UIを確認してみます。

おや?確かに、Descriptionでコメントによる補足は反映されていますが、型が全てstringになってしまっています。

Springdocではリクエストパラメータでは@Schemaで補足情報を加えようとすると、型を自動で変換することができず全てstringになってしまうようです。

この仕様が謎であったため、公式ドキュメントを眺めているとリクエストパラメータの時には@Parameterというアノテーションを利用すると良いようです。
@Parameterでもdescriptionexampleをそのまま指定することが出来ます。

public record SampleRequestDto(
        @Parameter(description = "文字列のパラメータ", example = "文字列")
        String stringField,

        @Parameter(description = "Integer型のパラメータ",  example = "1")
        Integer integerField,

        @Parameter(description = "Long型のパラメータ", example = "2")
        Long longField
) {
}

Swagger UIを確認してみます。

今度は、型が反映されています。

@Parameterではパラメータを入れる場所(ヘッダやクエリパラメータ等)を指定するin、空の値を許可するかどうかを示すallowEmptyValueなどのように、リクエストパラメータに特化した属性値をセットすることもできるため、今後はこちらを利用していきたいと思います。

おわりに

今回は、Springdocでアノテーションを利用して情報を付加するときに、リクエストパラメータには@Parameterを利用すべきであることを紹介しました。

では、また次回。

参考文献