Spectral を使って OpenAPI のエラーチェックを強化する


こんにちは、Gaji-Labo フロントエンドエンジニアの石垣です。

自分が携わっている案件では OpenAPIopenapi-generator-cli を使って API の仕様定義とサーバーのコード生成を行っているのですが、基本的には YAML ファイル上の schema を直接記述して作業しています。

このとき細かい記述ミスがあるとコード生成時にエラーが発生します。しかし openapi-generator-cli が出力するエラーメッセージはわかりにくいことが多いです。

たとえば、 openapi-generator-cli の公式で用意されている petstore.yaml というサンプルドキュメントを使ってエラーを確認してみます。

schemas:
  Order:
    title: Pet Order
    description: An order for a pets from the pet store
    type: object
    properties:
      id:
        type: integer
        format: int64
      id:
        type: integer
        format: int64
...

以上はサンプルドキュメントの状態から手元で id を重複させたものです。これを openapi-generator-cli でコード生成すると以下のエラーが表示されます。

> openapi-validator@1.0.0 og
> openapi-generator-cli generate

[[v3.0] petstore.yaml] [main] WARN  i.s.v.p.util.DeserializationUtils - Error snake-parsing yaml content
[[v3.0] petstore.yaml] io.swagger.v3.parser.util.DeserializationUtils$SnakeException: Duplicate field id
[[v3.0] petstore.yaml]  at io.swagger.v3.parser.util.DeserializationUtils$CustomSnakeYamlConstructor.getSingleData(DeserializationUtils.java:415)
[[v3.0] petstore.yaml]  at org.yaml.snakeyaml.Yaml.loadFromReader(Yaml.java:490)
[[v3.0] petstore.yaml]  at org.yaml.snakeyaml.Yaml.load(Yaml.java:416)
[[v3.0] petstore.yaml]  at io.swagger.v3.parser.util.DeserializationUtils.readYamlTree(DeserializationUtils.java:194)
[[v3.0] petstore.yaml]  at io.swagger.v3.parser.util.DeserializationUtils.deserializeIntoTree(DeserializationUtils.java:140)
[[v3.0] petstore.yaml]  at io.swagger.v3.parser.OpenAPIV3Parser.readContents(OpenAPIV3Parser.java:162)
[[v3.0] petstore.yaml]  at io.swagger.v3.parser.OpenAPIV3Parser.readLocation(OpenAPIV3Parser.java:91)
[[v3.0] petstore.yaml]  at io.swagger.parser.OpenAPIParser.readLocation(OpenAPIParser.java:16)
[[v3.0] petstore.yaml]  at org.openapitools.codegen.config.CodegenConfigurator.toContext(CodegenConfigurator.java:573)
[[v3.0] petstore.yaml]  at org.openapitools.codegen.config.CodegenConfigurator.toClientOptInput(CodegenConfigurator.java:631)
[[v3.0] petstore.yaml]  at org.openapitools.codegen.cmd.Generate.execute(Generate.java:457)
[[v3.0] petstore.yaml]  at org.openapitools.codegen.cmd.OpenApiGeneratorCommand.run(OpenApiGeneratorCommand.java:32)
[[v3.0] petstore.yaml]  at org.openapitools.codegen.OpenAPIGenerator.main(OpenAPIGenerator.java:66)
[[v3.0] petstore.yaml] Exception in thread "main" org.openapitools.codegen.SpecValidationException: There were issues with the specification. The option can be disabled via validateSpec (Maven/Gradle) or --skip-validate-spec (CLI).
[[v3.0] petstore.yaml]  | Error count: 1, Warning count: 0
[[v3.0] petstore.yaml] Errors: 
[[v3.0] petstore.yaml]  -Duplicate field id in `/Users/semigura/openapi-validator/petstore.yaml`
[[v3.0] petstore.yaml] 
[[v3.0] petstore.yaml]  at org.openapitools.codegen.config.CodegenConfigurator.toContext(CodegenConfigurator.java:604)
[[v3.0] petstore.yaml]  at org.openapitools.codegen.config.CodegenConfigurator.toClientOptInput(CodegenConfigurator.java:631)
[[v3.0] petstore.yaml]  at org.openapitools.codegen.cmd.Generate.execute(Generate.java:457)
[[v3.0] petstore.yaml]  at org.openapitools.codegen.cmd.OpenApiGeneratorCommand.run(OpenApiGeneratorCommand.java:32)
[[v3.0] petstore.yaml]  at org.openapitools.codegen.OpenAPIGenerator.main(OpenAPIGenerator.java:66)
[[v3.0] petstore.yaml] java -jar "/Users/semigura/openapi-validator/node_modules/@openapitools/openapi-generator-cli/versions/6.0.1.jar" generate --input-spec="/Users/tmp/Documents/works/openapi-validator/petstore.yaml" --generator-name="nodejs-express-server" --output="output" exited with code 1
[v3.0] petstore.yaml
  java -jar "/Users/semigura/openapi-validator/node_modules/@openapitools/openapi-generator-cli/versions/6.0.1.jar" generate --input-spec="/Users/semigura/openapi-validator/petstore.yaml" --generator-name="nodejs-express-server" --output="output"

Code generation failed

このエラーメッセージは Duplicate field id というエラーが表示されてはいますが重複しているフィールドがどこにあるのかが非常にわかりづらいです。

そこでより詳細なエラーメッセージを表示してくれるツールを探してみたところ、Spectral というツールを知ったので今回はその使い方についてまとめたいと思います。

Spectralとは

Spectral は、Stoplight が提供している OpenAPI のリンティングツールです。OpenAPIドキュメントに対して、様々なバリデーションルールを適用し、わかりやすいエラーメッセージを表示してくれます。npm パッケージとして提供されており、簡単にインストールすることができます。

まずはじめに、Spectral で使用するルールセットを設定する必要があります。
Spectral は標準のルールセットを提供しているので、それを活用できます。

echo 'extends: ["spectral:oas"]' > .spectral.yaml

これで Spectralがデフォルトで用意している OAS(OpenAPI Specification) のルールセットを使えるようになりました。

サンプルドキュメントのバリデーション

では実際に先程の petstore.yaml を使ってバリデーションを行ってみます。

spectral lint petstore.yaml

すると、以下のような詳細なエラーメッセージが表示されます。

/Users/semigura/openapi-validator/petstore.yaml
   4:6   warning  info-contact                Info object must have "contact" object.                        info
  26:20  warning  operation-description       Operation "description" must be present and non-empty string.  paths./pet.post.description
  50:20  warning  operation-description       Operation "description" must be present and non-empty string.  paths./pet.put.description
 195:20  warning  operation-description       Operation "description" must be present and non-empty string.  paths./pet/{petId}.post.description
 205:17  warning  operation-success-response  Operation must have at least one "2xx" or "3xx" response.      paths./pet/{petId}.post.responses
 228:20  warning  operation-description       Operation "description" must be present and non-empty string.  paths./pet/{petId}.delete.description
 243:17  warning  operation-success-response  Operation must have at least one "2xx" or "3xx" response.      paths./pet/{petId}.delete.responses
 255:20  warning  operation-description       Operation "description" must be present and non-empty string.  paths./pet/{petId}/uploadImage.post.description
 313:20  warning  operation-description       Operation "description" must be present and non-empty string.  paths./store/order.post.description
 382:17  warning  operation-success-response  Operation must have at least one "2xx" or "3xx" response.      paths./store/order/{orderId}.delete.responses
 394:17  warning  operation-success-response  Operation must have at least one "2xx" or "3xx" response.      paths./user.post.responses
 411:20  warning  operation-description       Operation "description" must be present and non-empty string.  paths./user/createWithArray.post.description
 413:17  warning  operation-success-response  Operation must have at least one "2xx" or "3xx" response.      paths./user/createWithArray.post.responses
 425:20  warning  operation-description       Operation "description" must be present and non-empty string.  paths./user/createWithList.post.description
 427:17  warning  operation-success-response  Operation must have at least one "2xx" or "3xx" response.      paths./user/createWithList.post.responses
 439:20  warning  operation-description       Operation "description" must be present and non-empty string.  paths./user/login.get.description
 490:20  warning  operation-description       Operation "description" must be present and non-empty string.  paths./user/logout.get.description
 492:17  warning  operation-success-response  Operation must have at least one "2xx" or "3xx" response.      paths./user/logout.get.responses
 502:20  warning  operation-description       Operation "description" must be present and non-empty string.  paths./user/{username}.get.description
 538:17  warning  operation-success-response  Operation must have at least one "2xx" or "3xx" response.      paths./user/{username}.put.responses
 565:17  warning  operation-success-response  Operation must have at least one "2xx" or "3xx" response.      paths./user/{username}.delete.responses
  618:9    error  parser                      Duplicate key: id                                              components.schemas.Order.properties.id

先ほども表示されていた Duplicate field id というエラーが、より詳細に表示されています。また、他にも様々なエラーが表示されていることがわかります。

このように Spectral はドキュメントの問題点を詳細に指摘してくれるため記述ミスの発見や修正が容易になります。

まとめ

今回は Spectral を使って OpenAPI ドキュメントのバリデーションを行う方法について紹介しました。
Spectral を使うことで、より詳細なエラーメッセージを表示してくれるため、問題の特定や修正が容易になります。
ぜひ活用してみてください。

Gaji-Labo フロントエンドエンジニア向けご案内資料

Gaji-Labo は Next.js, React, TypeScript 開発の実績と知見があります

フロントエンド開発の専門家である私たちが御社の開発チームに入ることで、バックエンドも含めた全体の開発効率が上がります。

「既存のサイトを Next.js に移行したい」
「人手が足りず信頼できるエンジニアを探している」
「自分たちで手を付けてみたがいまいち上手くいかない」

フロントエンド開発に関わるお困りごとがあれば、まずは一度お気軽に Gaji-Labo にご相談ください。

オンラインでのヒアリングとフルリモートでのプロセス支援にも対応しています。

Next.js, React, TypeScript の相談をする!

タグ


投稿者 Ishigaki Shotaro

未経験から Gaji-Labo に入社。現在は React/TypeScript/Next.js の案件で MUI を使ったコンポーネント組み込みを担当。プロジェクトチームのリードとして共に組み込み作業をしているメンバーの進行管理も行っています。休日はだいたい家で音楽を聴いており、たまにライブに出かけています。