【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プロジェクトで自動生成されたコードに独自のバリデータを適用することができます
![](https://incompengineer.com/wp-content/uploads/2022/08/pexels-photo-169573.jpeg)
是非フォローしてください
最新の情報をお伝えします