OpenAPIをSpring Bootで自動生成する場合に、リストや配列の情報を補完する方法

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

こちらの記事で、Spring BootからOpenAPIのドキュメントを自動生成する方法について説明されています。

tech.excite.co.jp

しかし、APIのレスポンスにListまたは配列の項目が存在していた場合に、アノテーションでの情報の補完に少し躓きました。

そこで今回は、Listまたは配列の項目が存在する場合のアノテーションの記述方法について紹介します。

今回扱う例

以下のようなコードからOpenAPIのドキュメントを自動生成することを考えます。

@RestController
@RequestMapping("example")
public class ExampleController {
    @GetMapping
    public ExampleResponse getResponse() {
        final ExampleResponse response = new ExampleResponse();

        response.setStringField("Hello, excite!");
        response.setArrayField(List.of("東京", "大阪", "福岡"));

        return response;
    }
}
@Data
public class ExampleResponse {
    private String stringField;

    private List<String> arrayField;
}

そのままアノテーションを付与して情報を補完すると、以下のようになるかと思います。 (ステータス500が返る場合については省略しています。)

@RestController
@RequestMapping("example")
@Tag(name = "example")
public class ExampleController {
    @GetMapping
    @Operation(summary = "example")
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "正常に処理が終了した場合",
                    content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExampleResponse.class))
            )
    })
    public ExampleResponse getResponse() {
        final ExampleResponse response = new ExampleResponse();

        response.setStringField("Hello, excite!");
        response.setArrayField(List.of("東京", "大阪", "福岡"));

        return response;
    }
}

@Data
@Schema(title = "サンプルのレスポンス")
public class ExampleResponse {
    @Schema(type = "string", title = "文字列のフィールド", example = "文字列", requiredMode = Schema.RequiredMode.REQUIRED)
    private String stringField;

    @Schema(type = "array", title = "arrayのフィールド", example = "[\"東京\",\"大阪\",\"福岡\"]", requiredMode = Schema.RequiredMode.REQUIRED)
    private List<String> arrayField;
}

このような記述からドキュメントを生成すると、以下のようなyamlのドキュメントができ上がります。

openapi: 3.0.1
info:
  title: API document of app api
  description: API document of app api
  version: 1.0.0
servers:
- url: http://localhost:8184
  description: URL in local
paths:
  /example:
    get:
      tags:
      - example
      summary: example
      operationId: getResponse
      responses:
        "200":
          description: 正常に処理が終了した場合
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExampleResponse'
components:
  schemas:
    ExampleResponse:
      title: サンプルのレスポンス
      required:
      - arrayField
      - stringField
      type: object
      properties:
        stringField:
          title: 文字列のフィールド
          type: string
          example: 文字列
        arrayField:
          title: arrayのフィールド
          type: array
          example:
          - 東京
          - 大阪
          - 福岡
          items:
            title: arrayのフィールド
            type: string
            example: "[\"東京\",\"大阪\",\"福岡\"]"

大体はうまく生成できているのですが、arrayFielditemsの部分が少し違和感のある結果になっています。

titlearrayのフィールドのままになっていますし、exampleも不正確です。(本当は、「東京」や「大阪」が入ってほしいはず)

では、どうするか

結論から言いますと、@ArraySchemaを使います。 そして、この@ArraySchema内の属性arraySchemaで配列やリスト自体の記述をし、schema属性で配列やリスト内の各要素に関する記述をします。

具体的には、

@Data
@Schema(title = "サンプルのレスポンス")
public class ExampleResponse {
    @Schema(type = "string", title = "文字列のフィールド", example = "文字列", requiredMode = Schema.RequiredMode.REQUIRED)
    private String stringField;

    @ArraySchema(
            arraySchema = @Schema(
                    type = "array", 
                    title = "arrayのフィールド", 
                    example = "[\"東京\",\"大阪\",\"福岡\"]", 
                    requiredMode = Schema.RequiredMode.REQUIRED
            ), 
            schema = @Schema(
                    type = "string", 
                    title = "arrayの中身", 
                    example = "東京"
            )
    )
    private List<String> arrayField;
}

のように記述します。

この記述の状態でyamlファイルを生成すると...

components:
  schemas:
    ExampleResponse:
      title: サンプルのレスポンス
      required:
      - stringField
      type: object
      properties:
        stringField:
          title: 文字列のフィールド
          type: string
          example: 文字列
        arrayField:
          title: arrayのフィールド
          type: array
          example:
          - 東京
          - 大阪
          - 福岡
          items:
            title: arrayの中身
            type: string
            example: 東京

このように、itemsの下についても生成を制御することができます。

ちなみに、この@ArraySchemaでは、最大(小)要素数や、要素がユニークかどうかのような設定も可能なようです。

StringやIntegerの配列やListを扱うときには、使用することを検討してもいいのではないでしょうか。

終わりに

今回は、Listまたは配列の項目が存在する場合のアノテーションの記述方法について紹介しました。

では、また次回。