You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flask-Restx中用@api.expect()验证多类型自定义字段?

在Flask-Restx中实现支持字符串、布尔值或列表类型的自定义字段

问题描述

需求:创建API模型时自定义字段,验证其值为字符串、布尔值或列表类型。

尝试方案1及错误

代码:

class CustomField(fields.Raw):
    __schema_type__ = ["String", "Boolean", "List"]
    __schema_example__ = "string or boolean or list"

    def format(self, value):
        if isinstance(value, str) or isinstance(value, bool) or isinstance(value, list):
            return value
        else:
            raise fields.MarshallingError(
                "Invalid type. Allowed types: str, bool, or list."
            )

出现错误:

jsonschema.exceptions.UnknownType: Unknown type 'String' for validator with schema:
    {'description': 'Value for the name type of foo',
     'example': 'string or boolean or list',
     'type': ['String', 'Boolean', 'List']}

尝试方案2及问题

代码:

class StringOrBooleanOrList(fields.Raw):
    """
    Marshal a value as a string or list.
    """

    def validate(self, value):
        if isinstance(value, str):
            return value
        elif isinstance(value, list):
            return value
        elif isinstance(value, bool):
            return value
        else:
            raise ValidationError(
                "Invalid input type. Must be a string or list or boolean"
            )

出现问题:

  • 字符串验证失败,提示“string value must be valid JSON”;
  • 列表和布尔值通过校验后,API返回错误:
{
  "errors": {
    "foo.0.value": "['bar'] is not of type 'object'"
  },
  "message": "Input payload validation failed"
}

错误原因分析

  1. 方案1错误原因:JSON Schema的类型名称遵循小写标准,且列表对应的类型是array而非List,代码中使用大写的String、Boolean、List会导致jsonschema无法识别类型。
  2. 方案2错误原因:
    • 继承fields.Raw后,默认的反序列化逻辑会尝试将输入解析为JSON,纯字符串会被判定为无效JSON;
    • 未正确设置字段的Schema类型,导致验证器默认认为字段应为object类型,从而触发类型不匹配错误。

正确实现方法

自定义字段需同时满足:符合JSON Schema标准、覆盖默认的序列化/反序列化逻辑、明确验证规则。以下是完整实现:

自定义多类型字段

from flask_restx import fields, ValidationError

class MultiTypeField(fields.Raw):
    # 定义JSON Schema允许的类型(小写,遵循标准)
    __schema_type__ = ["string", "boolean", "array"]
    
    def __init__(self, array_item_type=None, **kwargs):
        super().__init__(**kwargs)
        # 自定义Schema的oneOf规则,明确每个允许的类型(可按需扩展数组元素类型)
        schema_entries = [
            {"type": "string"},
            {"type": "boolean"}
        ]
        if array_item_type:
            schema_entries.append({
                "type": "array",
                "items": array_item_type.__schema__
            })
        else:
            schema_entries.append({"type": "array"})
            
        self.__schema__ = {
            "oneOf": schema_entries,
            "example": ["sample string", True, ["item1", "item2"]]
        }

    def format(self, value):
        """处理响应时的序列化验证"""
        if isinstance(value, (str, bool, list)):
            return value
        raise fields.MarshallingError("无效类型,允许的类型:str、bool、list")

    def parse(self, value):
        """处理请求时的反序列化验证"""
        if isinstance(value, (str, bool, list)):
            return value
        raise ValidationError("输入类型无效,必须为字符串、布尔值或列表")

字段使用示例

在API模型中引用该字段:

from flask_restx import Api, Namespace, Resource

api = Api(title="Multi-Type Field Demo")
ns = Namespace("demo")

# 定义模型,指定字段
example_model = ns.model("Example", {
    "foo": MultiTypeField(description="支持字符串、布尔值或列表的字段")
})

@ns.route("/test")
class TestResource(Resource):
    @ns.expect(example_model)
    @ns.marshal_with(example_model)
    def post(self):
        return api.payload

关键说明

  • Schema标准兼容:使用JSON Schema规定的小写类型名称(string、boolean、array),避免类型识别错误;
  • 明确验证规则:通过oneOf定义多类型允许规则,让OpenAPI文档更清晰,同时确保jsonschema验证逻辑正确;
  • 覆盖默认逻辑:重写format(序列化)和parse(反序列化)方法,替代fields.Raw的默认行为,解决字符串被当作JSON解析的问题;
  • 可扩展性:支持通过array_item_type参数指定数组元素的类型(如fields.String),进一步约束列表内容。

内容的提问来源于stack exchange,提问作者P_stack_gprogram

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 06:32:05