【Swagger】openapi.ymlに独自のバリデータを拡張していく!

OpenAPI定義ファイルに拡張機能を設定し、それに基づいて自動生成されたSpring Bootコードに独自のバリデータを適用する方法を説明します

拡張するにはOpenAPI Generatorのテンプレートをカスタマイズする必要があります


1. OpenAPI定義ファイルの設定

x-no-empty-string: true 拡張を設定したOpenAPI定義ファイル (openapi.yml) の例を示します

openapi: 3.0.0
info:
  title: Sample API
  version: 1.0.0
paths:
  /validate:
    post:
      summary: Validate request
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MyRequest'
      responses:
        '200':
          description: Success
components:
  schemas:
    MyRequest:
      type: object
      properties:
        items:
          type: array
          items:
            type: string
          description: "An array of strings"
          x-no-empty-string: true
      required:
        - items

2. Codegenテンプレートのカスタマイズ

OpenAPI Generatorのテンプレートをカスタマイズし、x-no-empty-string 拡張を認識して独自バリデータを追加します

2.1. OpenAPI Generatorのインストール

OpenAPI Generatorをインストールします

npm install @openapitools/openapi-generator-cli -g

2.2. カスタムテンプレートの作成

OpenAPI Generatorのテンプレートディレクトリを作成し、以下のようなカスタムテンプレートを用意します

⇓ ディレクトリ構成

my-templates/
└── spring
    ├── api
    │   └── ApiController.java.mustache
    └── model
        └── Model.java.mustache

Model.java.mustache ファイルをカスタマイズします(modelを生成)

{{#imports}}
import {{import}};
{{/imports}}

import javax.validation.constraints.*;
import {{classname}};

public class {{classname}} {

    {{#vars}}
    {{#isNotContainer}}
    @{{^isEnum}}{{^isPrimitiveType}}{{^isModel}}NotNull{{/isModel}}{{/isPrimitiveType}}{{/isEnum}}
    {{/isNotContainer}}
    {{#isListContainer}}
    {{#vendorExtensions.x-no-empty-string}}@NoEmptyString{{/vendorExtensions.x-no-empty-string}}
    {{/isListContainer}}
    private {{datatype}} {{name}};
    {{/vars}}
    
    // getters and setters
}

このテンプレートでは、x-no-empty-string 拡張を持つフィールドに対して @NoEmptyString アノテーションを追加しています

2.3. インターフェースを生成する

ApiControllerInterface.mustache はSpring Bootのコントローラーインターフェースを生成するテンプレートです

package {{basePackage}}.api;

import {{basePackage}}.model.{{classname}};
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 javax.validation.Valid;

@RestController
@RequestMapping("/api")
public interface {{classname}}Api {

    @PostMapping("/validate")
    String validate(@RequestBody @Valid {{classname}} myRequest);

}

3. 独自バリデータの実装

3.1. 独自バリデータアノテーションの作成

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Constraint(validatedBy = NoEmptyStringValidator.class)
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface NoEmptyString {
    String message() default "List contains empty string(s)";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

3.2. バリデータの実装

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.List;

public class NoEmptyStringValidator implements ConstraintValidator<NoEmptyString, List<String>> {
    @Override
    public void initialize(NoEmptyString constraintAnnotation) {
    }

    @Override
    public boolean isValid(List<String> value, ConstraintValidatorContext context) {
        if (value == null) {
            return true; // nullは別のバリデーションでチェックする場合もある
        }
        for (String s : value) {
            if (s == null || s.trim().isEmpty()) {
                return false;
            }
        }
        return true;
    }
}


4. コントローラーの作成

import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

@RestController
@Validated
public class MyController {

    @PostMapping("/validate")
    public String validate(@RequestBody @Valid MyRequest myRequest) {
        return "Valid request!";
    }
}

の手順を実行することで、OpenAPI定義ファイルに x-no-empty-string: true 拡張を追加し、Spring Bootプロジェクトで自動生成されたコードに独自のバリデータを適用することができます

是非フォローしてください

最新の情報をお伝えします