広告が嫌いですか? 行く 広告なし 今日

JSON スキーマの検証 発送前にAPI契約違反を検出

掲載日

JSONスキーマ検証は、API契約違反を元の段階で検出します。基本キーワード、Express用AJVミドルウェア、FastAPI統合、スキーマのずれ検出、およびOpenAPIの関係について学びます。

JSON スキーマ検証:API契約違反を配信前に検出 1

APIが返すフィールドがスキーマで定義されていない場合、またはリクエストボディに必須プロパティが欠けている場合、契約違反が発生しています。これらのバグは微妙で、しばしば静かで、生産環境で発見するのは非常に難しいものです。JSON スキーマ検証は、それらを早期に検出するための層です — その場所に近い、導入された場所に近いです。

このガイドでは、JSON スキーマの仕組み、Node.js、Python、AWSで使用すべき検証ライブラリ、そしてスキーマが現実と離れていないように保つ方法について説明します。

JSON スキーマとは

JSON スキーマは、JSONドキュメントの構造を記述するための語彙です。コードではありません — メタデータです。有効なJSONオブジェクトの外見を宣言したスキーマを書きます。その後、そのスキーマに対して検証を実行します。

スキーマそのものはJSONドキュメントです。最小限の例は次の通りです:

{
  "$schema": "https://json-schema.org/draft/2020-12",
  "type": "object",
  "properties": {
    "email": { "type": "string", "format": "email" },
    "age":   { "type": "integer", "minimum": 0 }
  },
  "required": ["email"]
}

それだけです。このスキーマを検証ライブラリに与え、任意のJSONペイロードを渡すと、通過または構造化された失敗リストが得られます。

核心キーワード

少数のキーワードで、実際の世界での検証ニーズの大部分をカバーできます:

キーワード 検証する内容
type 値のデータ型 "type": "string"
properties オブジェクトのフィールドの構造 "properties": { "name": { "type": "string" } }
required 存在すべきプロパティ "required": ["email", "password"]
additionalProperties 未知のプロパティが許容されるか "additionalProperties": false
enum 値が固定されたセットのいずれかでなければならない "enum": ["admin", "editor", "viewer"]
format セマンティックフォーマットチェック "format": "email" または "format": "date-time"
pattern 文字列が正規表現に一致するか "pattern": "^[a-z0-9-]+$"
$ref 別のスキーマへの参照 "$ref": "#/$defs/Address"

additionalProperties: false 特に注目すべきです。これはスキーマを厳格にすることで、スキーマに宣言されていないプロパティに対して検証エラーを発生させます。デフォルトでは無効で、つまりほとんどのスキーマは、明示的に選択しない限り、不正なフィールドを受け入れます。 properties 検証エラーをトリガーします。デフォルトでは無効で、つまりほとんどのスキーマは、明示的に選択しない限り、不正なフィールドを受け入れます。

完全なスキーマ:ユーザー登録リクエスト

ここでは、登録エンドポイントのリクエストボディに使用する完全なJSONスキーマを示します。これは、エンドポイントに触れるすべてのレイヤーで一度書くこと、そして検証するためのスキーマです。

{
  "$schema": "https://json-schema.org/draft/2020-12",
  "title": "UserRegistration",
  "type": "object",
  "required": ["email", "password", "username"],
  "additionalProperties": false,
  "properties": {
    "email": {
      "type": "string",
      "format": "email"
    },
    "password": {
      "type": "string",
      "minLength": 8
    },
    "username": {
      "type": "string",
      "pattern": "^[a-zA-Z0-9_]{3,32}$"
    },
    "role": {
      "type": "string",
      "enum": ["user", "admin"],
      "default": "user"
    },
    "birthDate": {
      "type": "string",
      "format": "date"
    }
  }
}

このスキーマを任意のペイロードに対してインタラクティブにテストできます。次の IO Tools JSON スキーマ検証ツール コードベースに組み込む前に使用できます。

APIリクエストボディの検証

Express + AJV

AJVはNode.js用の最も速いJSONスキーマ検証ライブラリです。次のExpressのミドルウェアは、ハンドラに到達する前にリクエストボディを検証します: AJVに、ドキュメント内のすべてのエラーを収集して、最初のエラーに止まらず、すべての検証失敗をクライアントに一括で返すように指示します。

import Ajv from "ajv";
import addFormats from "ajv-formats";

const ajv = new Ajv({ allErrors: true });
addFormats(ajv);

function validateBody(schema) {
  const validate = ajv.compile(schema);
  return (req, res, next) => {
    if (validate(req.body)) {
      return next();
    }
    res.status(400).json({
      error: "Validation failed",
      details: validate.errors,
    });
  };
}

// Usage
app.post("/register", validateBody(registrationSchema), registerHandler);

allErrors: true Pythonでは、FastAPIはPydanticを内部で使用しており、タイプアノテーションから自動的にJSONスキーマを生成します。外部からのJSONスキーマを使用している場合、

は、

は標準ライブラリです。 jsonschema AWS API Gateway

from jsonschema import validate, ValidationError

schema = { ... }  # your schema dict

try:
    validate(instance=request_body, schema=schema)
except ValidationError as e:
    return {"error": e.message}, 400

API Gatewayは、リクエストボディの検証をネイティブにサポートしています。モデル(これはJSONスキーマドキュメント)を定義し、そのメソッドに`schema`として関連付けます。検証に失敗したリクエストはゲートウェイレベルで拒否され、Lambda関数が実行される前に検証されます。これにより、一クラスのハンドラエラーが排除され、無効なトラフィックの冷スタート呼び出しも減少します。

複数のスキーマが共通の構造を持つ場合(例:住所、金額、ページネーションオブジェクトなど)は、その構造を一度に REQUEST_BODY で定義し、

で参照します。 $ref$defs

大きなプロジェクトでは、スキーマは別ファイルに保存され、 $defs URIにポイントしています。検証ライブラリが $ref:

{
  "$defs": {
    "Address": {
      "type": "object",
      "required": ["street", "city", "country"],
      "properties": {
        "street": { "type": "string" },
        "city":   { "type": "string" },
        "country": { "type": "string", "pattern": "^[A-Z]{2}$" }
      }
    }
  },
  "type": "object",
  "properties": {
    "billingAddress":  { "$ref": "#/$defs/Address" },
    "shippingAddress": { "$ref": "#/$defs/Address" }
  }
}

キーワードとURI解決をサポートしている場合、スキーマは遅延読み込みまたはレジストリから読み込まれます。AJVはこれを $ref を通じて処理します。 $id スキーマのずれ addSchema().

スキーマと実際のAPIがずれた状態を「スキーマのずれ」と呼びます。これはより一般的に起こります。スキーマは一度書かれ、APIが進化し、誰もスキーマを更新しません。

症状は微妙です。コード内でフィールド名が変更されたが、スキーマでは変更されていない — 検証はまだ通過します。なぜなら

がfalseに設定されていないためです。必須フィールドが実際にはオプションになった場合、コードがそのフィールドをチェックしなくなったため、スキーマではまだ必須とされていますが、クライアントがそのフィールドを送信しない場合に初めて問題が発覚します。 additionalProperties ずれを検出するには、スキーマ検証をテストとして扱う必要があります。一部のチームは、実際の応答フィクスチャーに対してスナップショットテストを自動化しています。他のチームは、CIでキャプチャされたAPIリクエストのセットに対してスキーマ検証を実行しています。要点は、スキーマを定期的にテストし、単にデプロイしただけではいけないということです。

JSON スキーマとOpenAPI

OpenAPI(以前はSwagger)は、リクエストおよびレスポンスボディをJSON スキーマで記述していますが、いくつかの変更を加えています。以前のバージョン(OpenAPI 2.0、3.0)はJSON スキーマのサブセットを使用し、拡張機能を追加しました。OpenAPI 3.1はJSON スキーマ draft 2020-12により近づいており、スキーマはほとんど互換性があります。

実際の違いは、OpenAPIはスキーマをより大きなドキュメントに包み、パス、操作、認証、サーバーを記述しています。JSON スキーマは単に検証契約です。もしスキーマファーストのAPIを構築している場合、各エンドポイントのJSON スキーマを書く、それを検証し、そのスキーマをそのままOpenAPIドキュメントに昇格させることができます。

既存データからスキーマを生成

新しいAPIでは手でスキーマを書くことが効果的です。既存のAPIでドキュメントがなく、動作が不明な場合、実際のペイロードからスキーマを生成してからそれを厳密に調整するのがより速い方法です。

(Python) および

ツールのように genson (Node.js) はサンプルJSONオブジェクトを受け取り、ドーフィーのスキーマを生成します。生成されたスキーマは常にあまりにも緩やかで、すべてがオプションになります。そして、 generate-schema は含まれていませんが、スタートポイントとして使えます。その後、 additionalProperties: falserequiredtype 、そして値が制限されている場所で enum を追加します。

このアプローチは、スキーマドキュメントが存在しない第三者APIを導入する場合にも役立ちます。複数の応答をスキーマ生成ツールに通して、出力の結果をマージし、その結果を検証用の契約として使用できます。


構造化データを受け取るすべてのレイヤーにJSON スキーマ検証が必要です — HTTPミドルウェア、メッセージキューのコンシューマ、データベースの書き込みパスです。契約違反が早期に発見されれば、修正コストは低いです。オンラインで JSON スキーマ検証ツール を用いることで、ライブラリ統合に前に進む前に、実際のペイロードに対してスキーマをプロトタイピングできます。これは、どの検証作業でも最初のステップとして適しています。

広告なしで楽しみたいですか? 今すぐ広告なしで

拡張機能をインストールする

お気に入りのブラウザにIOツールを追加して、すぐにアクセスし、検索を高速化します。

に追加 Chrome拡張機能 に追加 エッジ拡張 に追加 Firefox 拡張機能 に追加 Opera 拡張機能

スコアボードが到着しました!

スコアボード ゲームを追跡する楽しい方法です。すべてのデータはブラウザに保存されます。さらに多くの機能がまもなく登場します!

ニュースコーナー 技術ハイライト付き

参加する

価値ある無料ツールの提供を継続するためにご協力ください

コーヒーを買って