使用 Python 的 jsonschema 对 json 做验证

本文介绍如何在OpenStack中使用Python的jsonschema库来验证REST API响应的有效性,包括JSON Schema定义及其实现代码。

在OpenStack中, 使用了Python的 jsonschema包, 对json字符串做了验证.


Python JSON Schema Library

https://pypi.python.org/pypi/jsonschema


JSON Schema Introduction

http://json-schema.org/


做法比较简单

1) 定义一个文件 json schema. json schema 类似于一个模板定义文件, 定义了json中的节点名称, 节点值类型

以tempest中的一个schema定义为例 (tempest/api_schema/compute/agents.py)

[html]  view plain  copy
  1. list_agents = {  
  2.     'status_code': [200],  
  3.     'response_body': {  
  4.         'type': 'object',  
  5.         'properties': {  
  6.             'agents': {  
  7.                 'type': 'array',  
  8.                 'items': {  
  9.                     'type': 'object',  
  10.                     'properties': {  
  11.                         'agent_id': {'type': 'integer'},  
  12.                         'hypervisor': {'type': 'string'},  
  13.                         'os': {'type': 'string'},  
  14.                         'architecture': {'type': 'string'},  
  15.                         'version': {'type': 'string'},  
  16.                         'url': {'type': 'string', 'format': 'uri'},  
  17.                         'md5hash': {'type': 'string'}  
  18.                     },  
  19.                     'required': ['agent_id', 'hypervisor', 'os',  
  20.                                  'architecture', 'version', 'url', 'md5hash']  
  21.                 }  
  22.             }  
  23.         },  
  24.         'required': ['agents']  
  25.     }  
  26. }  


2) 使用jsonschema包, 对json字符串和json schema做对比, 进行验证

以下代码来自于 /tempest/common/rest_client.py. 

tempest对每一个REST api的返回值, 都使用json schema做了校验

[python]  view plain  copy
  1. @classmethod  
  2. def validate_response(cls, schema, resp, body):  
  3.     # Only check the response if the status code is a success code  
  4.     # TODO(cyeoh): Eventually we should be able to verify that a failure  
  5.     # code if it exists is something that we expect. This is explicitly  
  6.     # declared in the V3 API and so we should be able to export this in  
  7.     # the response schema. For now we'll ignore it.  
  8.     if resp.status in HTTP_SUCCESS:  
  9.         cls.expected_success(schema['status_code'], resp.status)  
  10.   
  11.         # Check the body of a response  
  12.         body_schema = schema.get('response_body')  
  13.         if body_schema:  
  14.             try:  
  15.                 jsonschema.validate(body, body_schema)  
  16.             except jsonschema.ValidationError as ex:  
  17.                 msg = ("HTTP response body is invalid (%s)") % ex  
  18.                 raise exceptions.InvalidHTTPResponseBody(msg)  
  19.         else:  
  20.             if body:  
  21.                 msg = ("HTTP response body should not exist (%s)") % body  
  22.                 raise exceptions.InvalidHTTPResponseBody(msg)  
  23.   
  24.         # Check the header of a response  
  25.         header_schema = schema.get('response_header')  
  26.         if header_schema:  
  27.             try:  
  28.                 jsonschema.validate(resp, header_schema)  
  29.             except jsonschema.ValidationError as ex:  
  30.                 msg = ("HTTP response header is invalid (%s)") % ex  
  31.                 raise exceptions.InvalidHTTPResponseHeader(msg)  


Java 中, 也有一个json-schema-validator的实现, 用法可以参考

http://stackoverflow.com/questions/14511468/java-android-validate-string-json-against-string-schema

Python 中,验证一个 JSON 数据是否满足某个 `JSON Schema` 可以使用第三方库 `jsonschema`。这是一个功能强大且广泛使用的库,支持完整的 JSON Schema 标准(如 Draft 7、Draft 2020 等)。 --- ### ✅ 安装 `jsonschema` 库 ```bash pip install jsonschema ``` --- ### ✅ 基本用法:验证 JSON 是否符合 Schema ```python import jsonschema from jsonschema import validate # 定义 JSON Schema schema = { "type": "object", "properties": { "name": {"type": "string"}, "age": {"type": "integer", "minimum": 0}, "email": {"type": "string", "format": "email"}, "is_active": {"type": "boolean"} }, "required": ["name", "age"] # 必填字段 } # 要验证的数据 data = { "name": "Alice", "age": 30, "email": "alice@example.com", "is_active": True } # 验证数据 try: validate(instance=data, schema=schema) print("✅ 数据有效,符合 schema") except jsonschema.exceptions.ValidationError as e: print("❌ 数据验证失败:", e.message) print("问题字段:", e.path) # 显示出错的字段路径 ``` --- ### ❌ 示例:触发验证错误 ```python invalid_data = { "name": "Bob", "age": -5 # 年龄不能为负数 } try: validate(instance=invalid_data, schema=schema) except jsonschema.exceptions.ValidationError as e: print("验证错误:", e.message) print("出错路径:", list(e.path)) # 输出: ['age'] ``` > 输出: ``` 验证错误: -5 is less than the minimum of 0 出错路径: ['age'] ``` --- ### 🔍 更复杂示例:数组、嵌套对象、条件校验 ```python complex_schema = { "type": "object", "properties": { "id": {"type": "integer"}, "tags": { "type": "array", "items": {"type": "string"}, "minItems": 1, "uniqueItems": True }, "profile": { "type": "object", "properties": { "birthday": {"type": "string", "format": "date"}, "height": {"type": "number", "minimum": 0} }, "required": ["birthday"] } }, "required": ["id", "tags"] } data = { "id": 1, "tags": ["python", "dev"], "profile": { "birthday": "1990-01-01", "height": 1.75 } } try: validate(instance=data, schema=complex_schema) print("✅ 复杂数据验证通过") except jsonschema.exceptions.ValidationError as e: print("验证失败:", e.message) ``` --- ### 🛠️ 使用 `Draft7Validator` 获取更详细的错误信息 ```python from jsonschema import Draft7Validator # 收集所有错误(而不是遇到第一个就停止) validator = Draft7Validator(schema) errors = sorted(validator.iter_errors(invalid_data), key=lambda e: e.path) for error in errors: print(f"错误: {error.message} -> 路径: {'/'.join(map(str, error.path))}") ``` --- ### 💡 提示与最佳实践 | 技巧 | 说明 | |------|------| | 使用 `"format"` 字段 | 如 `"email"`, `"date"`, `"datetime"`, `"uri"` 等(需安装 `strict-rfc3339` 或 `rfc3339-validator` 增强支持) | | `$ref` 引用复用 schema | 支持模块化定义大型 schema | | 预编译 schema | 对频繁验证场景,创建 `Validator` 实例提高性能 | | 自定义格式验证器 | 可扩展新的 `format` 规则 | --- ### ⚠️ 注意事项 - `jsonschema.validate()` 默认不开启所有 `format` 检查(例如 email 是否合法),需要设置 `format_checker` 才生效: ```python from jsonschema import FormatChecker try: validate( instance={"email": "not-an-email"}, schema={"type": "object", "properties": {"email": {"type": "string", "format": "email"}}}, format_checker=FormatChecker() ) except Exception as e: print("格式错误:", e.message) # 输出更准确的 email 格式错误 ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值