APIFlask入参为枚举值时,文档如何自动生成?

代码

from enum import Enum

from apiflask import APIFlask
from apiflask.fields import Integer
from apiflask.validators import OneOf

app = APIFlask(__name__, docs_ui='elements')


class APIFlaskEnum(Enum):
    @classmethod
    def choices(cls):
        return [i.value for i in cls]

    @classmethod
    def description(cls):
        return '\n\n'.join(f'{i.value}={i.name}' for i in cls)


class CategoryEnum(APIFlaskEnum):
    cat = 1
    dog = 2


@app.get('/say')
@app.input(dict(
    category=Integer(required=True, validate=OneOf(CategoryEnum.choices()))
), location='query')
@app.doc(description=CategoryEnum.description())
def say(data):
    """枚举值入参"""
    return CategoryEnum(data['category']).name


if __name__ == '__main__':
    app.run()

效果
image

以上为替代方案,但当参数有多个枚举类型时,该方案就不太适合了,有没有更优雅的方式解决呢?

还有一个是,要用两个\n才能显示出换行,有没有办法解决?

感谢!

优雅的方式可能是等 marshmallow 内置 Enum 支持的 PR 合并……

「当参数有多个枚举类型时」具体是指什么?没太明白。

要用两个\n才能显示出换行

description 可以用 Markdown,不过也都差不多。另外或许可以考虑把这个放到字段的 description 里面:

category = Integer(
    required = True,
    validate = OneOf(CategoryEnum.choices()),
    metadata = {'description': CategoryEnum.description()}
)
1 Like

谢谢回复!希望 marshmallow 能早日添加这个 feature

理想的情况是,这样写就能生成参数为枚举值的文档:

@app.input(dict(
    category=Integer(required=True, validate=OneOf(CategoryEnum))
), location='query')

根据建议优化了一下

from enum import Enum

from apiflask import APIFlask
from apiflask.fields import Integer
from apiflask.validators import OneOf

app = APIFlask(__name__, docs_ui='elements')


class APIFlaskEnum(Enum):
    @classmethod
    def choices(cls):
        return [i.value for i in cls]

    @classmethod
    def description(cls):
        desc = '<br>'.join(f'{i.value}={i.name}' for i in cls)
        if cls.__doc__ and cls.__doc__ != 'An enumeration.':
            desc = cls.__doc__ + '<br>' + desc
        return desc


class CategoryEnum(APIFlaskEnum):
    """类别"""
    cat = 1
    dog = 2


@app.get('/say')
@app.input(dict(
    category=Integer(required=True, validate=OneOf(CategoryEnum.choices()),
                     metadata={'description': CategoryEnum.description()})
), location='query')
def say(data):
    """枚举值入参"""
    return CategoryEnum(data['category']).name


if __name__ == '__main__':
    app.run()

效果

image

1 Like

好消息!marshmallow 3.18.0 已更新枚举字段 marshmallow.fields.Enum

安装

pip install -U marshmallow

示例代码

from enum import Enum

from marshmallow import Schema, fields


class CategoryEnum(Enum):
    cat = 1
    dog = 2


class Pet:
    def __init__(self, name, category):
        self.name = name
        self.category = category


class PetSchema(Schema):
    name = fields.String()
    category = fields.Enum(CategoryEnum)


class PetByValueSchema(Schema):
    name = fields.String()
    category = fields.Enum(CategoryEnum, by_value=True)


pet = Pet(name='Kitty', category=CategoryEnum.cat)
print(PetSchema().dump(pet))
print(PetByValueSchema().dump(pet))
# {'name': 'Kitty', 'category': 'cat'}
# {'name': 'Kitty', 'category': 1}

print(PetSchema().load({'name': 'Kitty', 'category': 'cat'}))
print(PetByValueSchema().load({'name': 'Kitty', 'category': 1}))
# {'name': 'Kitty', 'category': <CategoryEnum.cat: 1>}
# {'name': 'Kitty', 'category': <CategoryEnum.cat: 1>}

API 代码

import enum

from apiflask import APIFlask
from apiflask.fields import Integer
from marshmallow.fields import Enum


class CategoryEnum(enum.Enum):
    """类别"""
    cat = 1
    dog = 2


app = APIFlask(__name__, docs_ui='elements')


@app.get('/name')
@app.input(dict(
    category=Enum(CategoryEnum)
), location='query')
def name(data):
    return str(data['category'])


@app.get('/value')
@app.input(dict(
    category=Enum(CategoryEnum, by_value=Integer)
), location='query')
def value(data):
    return str(data['category'])


if __name__ == '__main__':
    app.run()
1 Like

试了一下,apispec 目前还没法正确为 Enum 字段解析 OpenAPI spec,估计还要等后续支持。