背景
PR #255 (issue #254 — 非 JSON Content-Type に付いた schema の検証スキップを surface)の multi-agent レビュー(/pr-review-toolkit:review-pr)で silent-failure-hunter が指摘。#254 以前から存在する既存ギャップ で、#254 のアダプタ/skip-surface 修正とは独立のためスコープ外として切り出し。
現状
RequestBodyValidator は requestBody.content の各 media type entry を走査し、schema が非配列(schema: "oops" / schema: null 等)なら loud な spec エラーを返す:
// src/Validation/Request/RequestBodyValidator.php
if (array_key_exists ('schema ' , $ mediaTypeSpec ) && !is_array ($ mediaTypeSpec ['schema ' ])) {
return new RequestBodyValidationResult ([
"Malformed 'requestBody.content[ \"{$ mediaType }\"].schema' ... expected object, got scalar. " ,
]);
}
一方 ResponseBodyValidator にはこの走査ガードが一切無い 。responses[$status].content の media type entry の schema が非配列でも事前検証されない。
問題
ResponseBodyValidator で spec の content map の schema が非配列のとき:
JSON media type の場合 — schema がそのまま OpenApiSchemaConverter::convert() に渡り、配列を期待する箇所で TypeError になる(RequestBodyValidator のコメントが「array_key_exists rather than isset so an explicit `schema: null` is also flagged ... producing a confusing TypeError instead of a spec-level error」と明記しているのと同じ事象)。
非 JSON media type の場合 — tech-debt(validation) — spec が宣言した非 JSON Content-Type のボディが診断なしで素通りする #254 で追加した skip 判定は isset($content[$matchedKey]['schema']) を使う。schema: null は isset が false を返すため「schema 無し」とみなされ、診断なしの silent success になる。リクエスト側は同じ schema: null を malformed spec エラーとして loud に落とすため、request/response で挙動が非対称。
contract-testing ツールの「malformed spec は隠さず surface する」原則に反し、かつ request 側との一貫性も欠く。
やること
ResponseBodyValidator::validate() に、RequestBodyValidator のループ前ガードと対称な malformed-schema 検出を追加する
content の各 media type entry について、array_key_exists('schema', ...) かつ !is_array(...) なら Malformed 'responses[...].content["..."].schema' 形式の spec エラーを返す
content / content[mediaType] 自体が非配列のケースも RequestBodyValidator のガード(Malformed 'requestBody.content' 等)に倣って揃えるか検討する
非 JSON skip 判定(tech-debt(validation) — spec が宣言した非 JSON Content-Type のボディが診断なしで素通りする #254 で追加した isset(...['schema']))は、上記ガード追加後は schema: null がガードで先に弾かれるため isset のままで一貫する
TDD: 非配列 schema(schema: "oops" / schema: null)を持つ response spec に対し、(a) JSON media type で TypeError ではなく spec エラーが返ること、(b) 非 JSON media type で silent success ではなく spec エラーが返ること、を検証する失敗テストを先に追加
ゴール
ResponseBodyValidator が非配列 schema を RequestBodyValidator と同じ粒度の loud な spec エラーとして surface する
JSON media type の非配列 schema で TypeError が出ない
非 JSON media type の schema: null が診断なしで素通りしない(request/response で挙動が揃う)
関連
背景
PR #255(issue #254 — 非 JSON Content-Type に付いた
schemaの検証スキップを surface)の multi-agent レビュー(/pr-review-toolkit:review-pr)で silent-failure-hunter が指摘。#254 以前から存在する既存ギャップで、#254 のアダプタ/skip-surface 修正とは独立のためスコープ外として切り出し。現状
RequestBodyValidatorはrequestBody.contentの各 media type entry を走査し、schemaが非配列(schema: "oops"/schema: null等)なら loud な spec エラーを返す:一方
ResponseBodyValidatorにはこの走査ガードが一切無い。responses[$status].contentの media type entry のschemaが非配列でも事前検証されない。問題
ResponseBodyValidatorで spec のcontentmap のschemaが非配列のとき:schemaがそのままOpenApiSchemaConverter::convert()に渡り、配列を期待する箇所でTypeErrorになる(RequestBodyValidatorのコメントが「array_key_exists rather than isset so an explicit `schema: null` is also flagged ... producing a confusing TypeError instead of a spec-level error」と明記しているのと同じ事象)。isset($content[$matchedKey]['schema'])を使う。schema: nullはissetが false を返すため「schema 無し」とみなされ、診断なしの silent success になる。リクエスト側は同じschema: nullを malformed spec エラーとして loud に落とすため、request/response で挙動が非対称。contract-testing ツールの「malformed spec は隠さず surface する」原則に反し、かつ request 側との一貫性も欠く。
やること
ResponseBodyValidator::validate()に、RequestBodyValidatorのループ前ガードと対称な malformed-schema 検出を追加するcontentの各 media type entry について、array_key_exists('schema', ...)かつ!is_array(...)ならMalformed 'responses[...].content["..."].schema'形式の spec エラーを返すcontent/content[mediaType]自体が非配列のケースもRequestBodyValidatorのガード(Malformed 'requestBody.content'等)に倣って揃えるか検討するisset(...['schema']))は、上記ガード追加後はschema: nullがガードで先に弾かれるためissetのままで一貫するschema(schema: "oops"/schema: null)を持つ response spec に対し、(a) JSON media type で TypeError ではなく spec エラーが返ること、(b) 非 JSON media type で silent success ではなく spec エラーが返ること、を検証する失敗テストを先に追加ゴール
ResponseBodyValidatorが非配列schemaをRequestBodyValidatorと同じ粒度の loud な spec エラーとして surface するschemaでTypeErrorが出ないschema: nullが診断なしで素通りしない(request/response で挙動が揃う)関連
schemaの検証スキップ surface(同種・直接の親)src/Validation/Request/RequestBodyValidator.phpの per-media-type malformed ガード(対称実装の参照元)