バリデーションエラーのカスタマイズ方法を教えてください



APIGWのroutingに設定できるspecでのバリデーションエラーはカスタマイズすることができません。従って独自のバリデーションエラーをカスタム定義したい場合は、Scenarioのrequest_validationブロックで実装する必要があります。

以下のような簡単なScenarioを例に解説します。

- category: example
  name: customValidationError
  uri: /v1/customValidationErrors
  method: POST
  request_timeout: 60
  connect_timeout: 60
  routing_auto_generation_mode: true
  commands:
    - command: request_validation
      kwargs:
        headers:
          type: object
          properties:
            Content-Type:
              type: string
              enum:
                - application/json
          required:
            - Content-Type
        body:
          type: object
          properties:
            name:
              type: string
            description:
              type: string
          required:
            - name


デフォルトのバリデーションエラーは以下のようなフォーマットで返却されます。

>>> r = await callout(path="/v1/customValidationErrors",↵
... method=POST,↵
... headers={"Content-Type": "application/json"},↵
... body={"name": 12345})↵
... ↵
↵
>>> print(json.dumps(json.loads(r.body), indent=4))↵
... ↵
↵
{
    "errorCode": 400,
    "errorMessage": "Invalid request",
    "moreInfo": "12345 is not of type 'string'\n\nFailed validating 'type' in schema['properties']['name']:\n    {'type': 'string'}\n\nOn instance['name']:\n    12345"
}
>>>


次にScenarioを以下のように修正してみてください。具体的にはrequest_validationコマンドのexcept_codeオプションを追加しています。

- category: example
  name: customValidationError
  uri: /v1/customValidationErrors
  method: POST
  request_timeout: 60
  connect_timeout: 60
  routing_auto_generation_mode: true
  commands:
    - command: request_validation
      kwargs:
        headers:
          type: object
          properties:
            Content-Type:
              type: string
              enum:
                - application/json
          required:
            - Content-Type
        body:
          type: object
          properties:
            name:
              type: string
            description:
              type: string
          required:
            - name
        except_code: 'raise Error(400, body={"message": f''{".".join(list(e.relative_path))}に指定されている{e.instance}は不正です''})'


>>> r = await callout(path="/v1/customValidationErrors",↵
... method=POST,↵
... headers={"Content-Type": "application/json"},↵
... body={"name": 12345})↵
... ↵
↵
>>> print(json.dumps(json.loads(r.body), indent=4))↵
... ↵
↵
{
    "message": "nameに指定されている12345は不正です"
}
>>>


Tip

except_codeの実行時名前空間には、jsonschemaバリデーション時に発生した例外オブジェクトが格納されます。変数名はeです。request_validationコマンドに設定されている各スキーマが正しい場合、eにはjsonschema.exceptions.ValidationErrorが格納されます。スキーマが不正の場合は、jsonschema.exceptions.SchemaErrorが格納されることに注意してください。バリデーションエラーのハンドリングについてはhttps://python-jsonschema.readthedocs.io/en/stable/errors/を参考にしてください。

Warning

except_codeブロックで例外を発出しない場合は、request_validationコマンドは正常終了扱いとなり、次のコマンドの実行に遷移することに注意してください。本機能はv21.2LTS-patch20210625以降のversionでのみ利用できます。