如何在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错误原因:JSON Schema的类型名称遵循小写标准,且列表对应的类型是
array而非List,代码中使用大写的String、Boolean、List会导致jsonschema无法识别类型。 - 方案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
相关产品推荐
相关产品推荐

