{"id":13473357,"url":"https://github.com/lzjun567/flask-siwadoc","last_synced_at":"2026-03-17T22:07:42.302Z","repository":{"id":37272526,"uuid":"499865893","full_name":"lzjun567/flask-siwadoc","owner":"lzjun567","description":"flask-siwadoc is a flask data validator and openapi document generator automaticly","archived":false,"fork":false,"pushed_at":"2025-12-16T08:42:47.000Z","size":1075,"stargazers_count":57,"open_issues_count":12,"forks_count":13,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-17T03:58:43.874Z","etag":null,"topics":["flask","openapi","swagger","validator"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lzjun567.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-06-04T15:33:16.000Z","updated_at":"2025-12-16T08:42:50.000Z","dependencies_parsed_at":"2024-01-13T18:34:12.347Z","dependency_job_id":null,"html_url":"https://github.com/lzjun567/flask-siwadoc","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/lzjun567/flask-siwadoc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lzjun567%2Fflask-siwadoc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lzjun567%2Fflask-siwadoc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lzjun567%2Fflask-siwadoc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lzjun567%2Fflask-siwadoc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lzjun567","download_url":"https://codeload.github.com/lzjun567/flask-siwadoc/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lzjun567%2Fflask-siwadoc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30633240,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-17T17:32:55.572Z","status":"ssl_error","status_checked_at":"2026-03-17T17:32:38.732Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["flask","openapi","swagger","validator"],"created_at":"2024-07-31T16:01:02.925Z","updated_at":"2026-03-17T22:07:42.238Z","avatar_url":"https://github.com/lzjun567.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# flask-siwadoc\n\n**flask-siwadoc**是一个兼具**数据校验**和openapi(swagger)**文档自动生成**的项目\n\n## 特性\n\n### 1、API接口自动生成文档\n\n只需要初始化一个`siwa=SiwaDoc(app)`,利用装饰器 `siwa.doc()`修饰flask视图函数，即可将该视图对应的路由加入openapi的paths中。\n\n### 2、支持多种参数指定\n\n可以将请求参数放置在 `query`、`path`、`header`、`cookie`、`body(json、formdata)`5种不同的地方，完全支持openapi规范所定义的5种参数方式。\n\n### 3、参数校验与自动转换\n\n基于`pydantic`，请求参数可自动转换为对应的数据类型\n\n### 4、ui切换\n\nflask-siwadoc内置了`swagger`（默认）、`redoc`、`rapidoc`等多种UI界面\n\n### 5、支持标签与分组\n\n### 6、可设置访问权限\n\n配置参数：\n* SIWA_USER：登录用户名\n* SIWA_PASSWORD: 登录密码\n\n只有同时设置了用户名和密码访问文档才需要登录权限，该场景用在正式环境中，防止接口文档被匿名访问\n\n## 安装\n\n```\npip install flask-siwadoc\n```\n\n## 快速开始\n\n### example 1\n\n```python\nfrom flask import Flask\nfrom flask_siwadoc import SiwaDoc\n\napp = Flask(__name__)\nsiwa = SiwaDoc(app, title=\"siwadocapi\", description=\"一个自动生成openapi文档的库\")\n\n\n# 或者使用工厂模式\n# siwa = SiwaDoc(title=\"siwadocapi\", description=\"一个自动生成openapi文档的库\")\n# siwa.init_app(app)\n\n\n@app.route(\"/hello\", methods=[\"GET\"])\n@siwa.doc()\ndef hello():\n    return \"hello siwadoc\"\n\n\nif __name__ == '__main__':\n    app.run()\n```\n\n运行后，访问 [http://127.0.0.1:5000/docs](http://127.0.0.1:5000/docs) 就可以看到openapi文档页面\n\n![20220722101346.png](./screnshots/20220722101346.png)\n\n### example 2：指定 query 参数\n```python\nfrom pydantic import BaseModel, Field\n\nUSERS = [\n    {\"username\": \"siwa1\", \"id\": 1},\n    {\"username\": \"siwa2\", \"id\": 2},\n    {\"username\": \"siwa3\", \"id\": 3},\n]\n\n\nclass QueryModel(BaseModel):\n    page: int = Field(default=1, title=\"current page number\")\n    size: int = Field(default=20, title=\"size of page\", ge=10, le=100)\n    keyword: str = None\n\n\n@app.route(\"/users\", methods=[\"GET\"])\n@siwa.doc(query=QueryModel, tags=[\"user\"], group=\"user\")\ndef users_list(query: QueryModel):\n    \"\"\"\n    user list\n    \"\"\"\n    print(query.page)  # 1\n    return {\"data\": USERS[:query.size]}\n```\n\n以查询参数方式接收数据时，例如：`/path?page=1\u0026size=10`\n\n1. 定义一个继承自`pydantic.BaseModel`的子类：`QueryModel`\n2. `@siwa.doc(query=QueryModel)` ：`doc`装饰器中接收名为`query`的对象，用于在文档中展示参数列表\n3. `users_list(query: QueryModel)` 视图函数中定义名字为`query`的参数，主要是方便开发者直接通过`query`对象获取参数值\n\n![20220722100939.png](./screnshots/20220722100939.png)\n\n### example3: 指定 header 参数\n\n```python\nclass TokenModel(BaseModel):\n    token: str\n\n\n@app.route(\"/me\", methods=[\"GET\"])\n@siwa.doc(header=TokenModel, tags=['auth'], group='admin')\ndef param_in_header():\n    token = request.headers.get(\"token\")\n    print(\"token:\", token)\n    return {\"token\": token}\n```\n\nheader中的参数可直接通过 `request.headers.get` 获取\n\n![20220722102652.png](./screnshots/20220722102652.png)\n\n### example4:指定 cookie 参数\n\n```python\nclass CookieModel(BaseModel):\n    foo: str\n\n\n@app.route(\"/cookie\", methods=[\"GET\"])\n@siwa.doc(cookie=CookieModel, tags=['auth'], group='admin')\ndef param_in_cookie():\n    foo = request.cookies.get(\"foo\")\n    print(\"foo:\", foo)\n    return {\"foo\": foo}\n\n```\n\n![](./screnshots/20220722103100.png)\n\n### example5 :指定请求 body\n\n以请求body接收数据时，例如：\n\n```shell\ncurl -X 'POST' \\\n  'http://127.0.0.1:5000/user/login' \\\n  -H 'accept: */*' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"password\": \"string\",\n  \"username\": \"string\"\n}'\n```\n\n```python\nclass LoginModel(BaseModel):\n    username: str\n    password: str\n\n\n@app.route(\"/user/login\", methods=[\"POST\"])\n@siwa.doc(body=LoginModel, tags=['auth'])\ndef user_login(body: LoginModel):\n    return {\n        \"username\": body.username,\n        \"password\": body.password,\n        \"id\": 1}\n```\n\n1. 定义一个继承自`pydantic.BaseModel`的子类：`LoginModel`\n2. `@siwa.doc(body=LoginModel)` ：`doc`装饰器中接收名为`body`的对象，用于在文档中展示参数列表\n3. `users_list(body: LoginModel)` 视图函数中定义名字为`body`的参数，方便开发者直接通过`body`对象获取参数值\n\n![20220722104304.png](./screnshots/20220722104304.png)\n\n### example6: 使用formdata请求\n\nexample5中使用`json`作为请求体，当请求文件等复杂数据类型时，需要使用`formdata`\n\n#### 情形一：没有文件等复杂数据类型时，例如\n```python\nclass UserModel(BaseModel):\n    id: int\n    username: str\n\n\n@app.post('/form')\n@siwa.doc(form=UserModel)\ndef test_form(form: UserModel):\n    print(form.id)\n    print(form.username)\n    return form.username\n```\n1. 定义一个继承自`pydantic.BaseModel`的子类：`UserModel`\n2. `@siwa.doc(form=UserModel)` ：`doc`装饰器中接收名为`form`的对象，用于在文档中展示参数列表\n3. `test_form(form: UserModel)` 视图函数中定义名字为`form`的参数，方便开发者直接通过`form`对象获取参数值\n\n![20230310094000.png](./screnshots/20230310094000.png)\n\n#### 情形二：请求体中包含基础数据类型数据，也包含文件对象参数时，例如：\n```python\n\n@app.post('/form_with_files')\n@siwa.doc(form=UserModel, files={'file1': {\"required\": True, \"single\": False}, 'file2': {\"required\": False, \"single\": True}})\ndef test_form_with_files(form: UserModel, files: dict):\n    print(form.id)\n    print(form.username)\n    print(files.keys())\n    return form.username\n```\n1. 定义一个继承自`pydantic.BaseModel`的子类：`UserModel`\n2. `@siwa.doc(form=UserModel, files={'file1': {\"required\": True, \"single\": False}, 'file2': {\"required\": False, \"single\": True}})` ：`doc`装饰器中接收名为`form`的对象、名为`files`的字典。`form`对象用于在文档中展示参数列表，`files`字典用于定义文件参数列表以及文件参数配置（`required`配置此文件参数是否必传，默认`False`；`single`配置此文件参数接收单文件还是文件列表，默认`True`）\n3. `test_form_with_files(form: UserModel, files: dict)` 视图函数中定义名字为`form`的参数，方便开发者直接通过`form`对象获取基本数据类型的参数值; `files`字典用于获取文件对象\n\n![20230310094500.png](./screnshots/20230310094500.png)\n\n#### 情形三：请求体中只包含文件对象参数时，例如：\n```python\n\n@app.post('/form_only_files')\n@siwa.doc(form=BaseModel, files={'file1': {\"required\": True, \"single\": False}, 'file2': {\"required\": False, \"single\": True}})\ndef test_form_only_files(files: dict):\n    print(files.keys())\n\n    return 'success'\n```\n\n1. `@siwa.doc(form=BaseModel, files={'file1': {\"required\": True, \"single\": False}, 'file2': {\"required\": False, \"single\": True}})` ：`doc`装饰器中接收名为`form`的对象、名为`files`的字典。`form`对象指定为基类`BaseModel`，`files`同情形二\n2. `test_form_only_files(files: dict)` 视图函数中定义名字`files`的字典，用于获取文件对象\n\n![20230310094400.png](./screnshots/20230310094400.png)\n\n### example7: 指定返回体 responses\n\n需要告诉客户端接口返回的字段时，指定参数`resp`\n\n```python\nclass UserModel(BaseModel):\n    id: int\n    username: str\n\n\n@app.route(\"/users\", methods=[\"GET\"])\n@siwa.doc(query=QueryModel, resp=UserModel)\ndef users_list(query: QueryModel):\n    \"\"\"\n    user list\n    \"\"\"\n    return {\"data\": USERS[:query.size]}\n```\n\n1. 定义一个继承自`pydantic.BaseModel`的子类：`UserModel`\n2. `@siwa.doc(resp=UserModel)` ：`doc`装饰器中接收名为`resp`的对象，用于在文档中展示返回的字段列表\n\n![20220722110623.png](./screnshots/20220722110623.png)\n\n### example8: 指定标签分类 tags\n\n项目中如果接口太多，我们可以对接口根据业务划分不同的模块标签来分类管理。\n\n```python\n@siwa.doc(resp=UserModel, tags=[\"user\"])\n```\n\n指定`tags`参数，tags参数是一个列表，一个接口可支持多个标签。\n\n\n### example9: 指定分组  group\n\n除了可以指定标签外，我们还可以指定分组\n\n```python\n@app.route(\"/admin/login\", methods=[\"POST\"])\n@siwa.doc(body=LoginModel, resp=UserModel, tags=['auth'], group='admin')\ndef admin_login(body: LoginModel):\n    return {\"username\": body.username, \"id\": 1}\n```\n\n\n完整示例可参考 [example.py](./example/__init__.py)\n\n### UI切换\n\n文档默认使用`swagger`进行渲染，你可以在路径上指定参数`?ui=swagger`切换成 `swagger` 渲染文档。\n\n```python\nhttp://127.0.0.1:5000/docs/?ui=swagger\n```\n\n![20220604203420.png](./screnshots/20220604203420.png)\n\n### 扩展\n\n数据校验报错时，flask-siwadoc 会抛出异常`flask_siwadoc.error.ValidationError`，ValidationError 继承自`pydantic.ValidationError`\n\n例如：\n\n```python\n\nclass QueryModel(BaseModel):\n    keyword: str\n\n\n@app.route(\"/users\", methods=[\"GET\"])\n@siwa.doc(query=QueryModel, tags=[\"user\"])\ndef hello(query: QueryModel):\n    print(query)\n    return \"hello\"\n```\n\n该接口中，keyword是必选的查询参数，如果url中没有keyword参数，就会抛出异常\n\n```\nraise ValidationError(e)\nflask_siwadoc.error.ValidationError: 2 validation errors for Auth\n    username\nfield required (type=value_error.missing)\npassword\nfield required (type=value_error.missing)\n```\n\n使用flask的 `errorhandler()` 装饰函数来注册`ValidationError`错误，这样错误异常就可以被`validate_error`函数捕获，开发者可以给前端直接一个友好的错误响应体\n\n```python\n@app.errorhandler(ValidationError)\ndef validate_error(e: ValidationError):\n    return dict(code=-1, msg=\"请求参数错误\", error_info=e.errors()), 400\n```\n\n![20220604214851.png](./screnshots/20220604214851.png)\n\nreference\n\n1. https://pydantic-docs.helpmanual.io/\n2. https://github.com/tiangolo/fastapi\n3. https://github.com/bauerji/flask-pydantic\n4. https://github.com/kemingy/flaskerk\n\n任何问题欢迎发issue或者加我微信 lzjun567 交流，欢迎PR， 如果对你有帮助或者给你的工作带来了极大的便利，可考虑赞赏作者\n\n![赞赏](./screnshots/6802366f4419fd9db9fb3c730f873d2.jpg)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flzjun567%2Fflask-siwadoc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flzjun567%2Fflask-siwadoc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flzjun567%2Fflask-siwadoc/lists"}