Flask:如何自动化 OpenAPI v3 文档?

1Z1*_*Z10 14 python flask python-3.x openapi

我需要记录一个用纯 Flask 2 编写的 API,并且我正在寻找执行此操作的统一方法。我找到了不同的可行解决方案,但作为 Python 和 Flask 的新手,我无法在其中进行选择。我找到的解决方案是:

为了分离不同的 API 端点,我使用 Flask 蓝图。MWE的结构如下:

项目结构

我首先定义了两个简单的域对象:AuthorBook

# author.py
class Author:
    def __init__(self, id: str, name: str):
        self.id = id
        self.name = name

# book.py
class Book:
    def __init__(self, id: str, name: str):
        self.id = id
        self.name = name
Run Code Online (Sandbox Code Playgroud)

接下来,我使用两个单独的蓝图为它们创建了一个简单的 GET 端点。

# author_apy.py
import json

from flask import Blueprint, Response

from domain.author import Author

author = Blueprint("author", __name__, url_prefix="/authors")


@author.get("/")
def authors():
    authors: list[Author] = []

    for i in range(10):
        author: Author = Author(str(i), "Author " + str(i))
        authors.append(author)

    authors_dicts = [author.__dict__ for author in authors]
    return Response(json.dumps(authors_dicts), mimetype="application/json")
Run Code Online (Sandbox Code Playgroud)

# book_api.json
import json

from flask import Blueprint, Response

from domain.book import Book

book = Blueprint("book", __name__, url_prefix="/books")


@book.get("/")
def books():
    books: list[Book] = []

    for i in range(10):
        book: Book = Book(str(i), "Book " + str(i))
        books.append(book)

    books_dicts = [book.__dict__ for book in books]
    return Response(json.dumps(books_dicts), mimetype="application/json")
Run Code Online (Sandbox Code Playgroud)

最后我只是将两个蓝图都注册到了 Flask 应用程序下。

# app.py
from flask import Flask
from api.author.author_api import author
from api.book.book_api import book

app = Flask(__name__)
app.register_blueprint(author, url_prefix="/authors")
app.register_blueprint(book, url_prefix="/books")


@app.get('/')
def hello_world():
    return 'Flask - OpenAPI'


if __name__ == '__main__':
    app.run()
Run Code Online (Sandbox Code Playgroud)

整个源代码也可以在GitHub上找到。

考虑到这个最小的工作示例,我想知道自动生成 OpenAPI v3 yaml/JSON 文件(例如在 /api-doc.yaml 端点上公开)的最快方法是什么。

PS:这是我使用 Python 和 Flask 的第一个 API。我正在尝试重现我能够使用Spring-BootSpringDoc做的事情

1Z1*_*Z10 7

按照从 Flask 迁移到 FastAPI 的建议,我尝试了一下并重写了问题的Flask-Example 。源代码也可在GitHub上获取。

该项目的结构几乎相同,但有一些可用的附加功能(例如 CORS 中间件): 在此输入图像描述

域的模型略有不同,并且扩展了PydanticBaseModel

# author.py
from pydantic import BaseModel


class Author(BaseModel):
    id: str
    name: str
Run Code Online (Sandbox Code Playgroud)

# book.py
from pydantic import BaseModel


class Book(BaseModel):
    id: str
    name: str
Run Code Online (Sandbox Code Playgroud)

对于 FastAPI ,APIRouter相当于Flask蓝图。以下是作者的两个控制器

# author_api.py
from fastapi import APIRouter

from domain.author import Author

router = APIRouter()


@router.get("/", tags=["Authors"], response_model=list[Author])
def get_authors() -> list[Author]:
    authors: list[Author] = []

    for i in range(10):
        authors.append(Author(id="Author-" + str(i), name="Author-Name-" + str(i)))

    return authors
Run Code Online (Sandbox Code Playgroud)

和书

# book_api.py
from fastapi import APIRouter

from domain.book import Book

router = APIRouter()


@router.get("/", tags=["Books"], response_model=list[Book])
def get_books() -> list[Book]:
    books: list[Book] = []

    for i in range(10):
        books.append(Book(id="Book-" + str(i), name="Book-Name-" + str(i)))

    return books
Run Code Online (Sandbox Code Playgroud)

值得注意的是,由于 Pydantic,API 端点的响应模型是使用 Python 类型定义的。然后,这些对象类型将转换为 OpenAPI 文档的 JSON 模式。

最后,我只是在 FastAPI 对象下注册/包含 APIRouters,并添加了 CORS 的配置。

# app.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from domain.info import Info
from api.author.author_api import router as authors_router
from api.book.book_api import router as books_router

app = FastAPI()
app.include_router(authors_router, prefix="/authors")
app.include_router(books_router, prefix="/books")

app.add_middleware(CORSMiddleware,
                   allow_credentials=True,
                   allow_origins=["*"],
                   allow_methods=["*"],
                   allow_headers=["*"],
                   )


@app.get("/", response_model=Info)
def info() -> Info:
    info = Info(info="FastAPI - OpenAPI")
    return info
Run Code Online (Sandbox Code Playgroud)

生成的 OpenAPI 文档可在端点访问/openapi.json,而 UI(又名 Swagger UI、Redoc)可在/docs

在此输入图像描述

/redoc

在此输入图像描述

总而言之,这是自动生成的 JSON 格式的 OpenAPI v3 文档,可用于轻松生成其他语言的 API 客户端(例如使用OpenAPI-Generator 工具)。

{
  "openapi": "3.0.2",
  "info": {
    "title": "FastAPI",
    "version": "0.1.0"
  },
  "paths": {
    "/authors/": {
      "get": {
        "tags": [
          "Authors"
        ],
        "summary": "Get Authors",
        "operationId": "get_authors_authors__get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "title": "Response Get Authors Authors  Get",
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Author"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/books/": {
      "get": {
        "tags": [
          "Books"
        ],
        "summary": "Get Books",
        "operationId": "get_books_books__get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "title": "Response Get Books Books  Get",
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Book"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/": {
      "get": {
        "summary": "Info",
        "operationId": "info__get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Info"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Author": {
        "title": "Author",
        "required": [
          "id",
          "name"
        ],
        "type": "object",
        "properties": {
          "id": {
            "title": "Id",
            "type": "string"
          },
          "name": {
            "title": "Name",
            "type": "string"
          }
        }
      },
      "Book": {
        "title": "Book",
        "required": [
          "id",
          "name"
        ],
        "type": "object",
        "properties": {
          "id": {
            "title": "Id",
            "type": "string"
          },
          "name": {
            "title": "Name",
            "type": "string"
          }
        }
      },
      "Info": {
        "title": "Info",
        "required": [
          "info"
        ],
        "type": "object",
        "properties": {
          "info": {
            "title": "Info",
            "type": "string"
          }
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

为了启动应用程序,我们还需要一个用于生产的 ASGI 服务器,例如 UvicornHypercorn。我使用 Uvicorn 并且使用以下命令启动该应用程序:

uvicorn app:app --reload
Run Code Online (Sandbox Code Playgroud)

然后它就可以在您机器的端口8000上使用。


qew*_*jhb 3

我鼓励你将你的项目切换到 FastAPI,它与 Flask 没有太大不同,也没有更困难。

有关生成 OpenAPI 架构的 FastAPI 文档

它不仅允许您轻松生成 OpenAPI 文档/规范。它也是异步的、更快、更现代。

另请参阅FastAPI 替代方案、灵感和比较来了解差异。

特别是上面链接中的引用应该解释为什么做你尝试做的事情可能不是最好的主意:

Flask REST 框架

有几个 Flask REST 框架,但在投入时间和精力研究它们之后,我发现许多都已停止或放弃,并且存在一些使它们不适合的长期问题。

  • 除了与其他框架进行比较的信息之外,更好的答案是展示一个实际的示例:至少有一条来自OP问题的路线为FastAPI移植+自动生成的FastAPI文档(屏幕截图显示了如何看起来像)。虽然与 Flask 的比较很有趣,但这不是问题所在。 (2认同)
  • Flask-Smorest(使用 apispec)可以为 Flask 做同样的事情,并且由 Marshmallow 团队积极维护。 (2认同)