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

标签 python python-3.x flask openapi

我需要记录一个用纯 Flask 2 编写的 API,我正在寻找什么是这样做的综合方法。
我找到了不同的可行解决方案,但我是 Python 和 Flask 的新手,我无法在其中进行选择。我找到的解决方案是:

  • https://github.com/marshmallow-code/apispec
  • https://github.com/jmcarp/flask-apispec
  • https://github.com/marshmallow-code/flask-smorest

  • 为了分离不同的 API 端点,我使用了 Flask 蓝图。
    MWE的结构如下:
    Project Structure
    我首先定义了两个简单的域对象,作者 预订 .
    # 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
    
    接下来,我使用两个单独的蓝图为它们创建了一个简单的 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")
    
    # 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")
    
    最后我只是在 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()
    
    整个源代码也可以在 GitHub 上找到.
    考虑到这个最小的工作示例,我想知道自动生成 OpenAPI v3 yaml/JSON 文件的最快方法是什么,例如在/api-doc.yaml 端点上公开。
    PS:这是我第一个使用 Python 和 Flask 的 API。我正在尝试重现我能用 Spring-Boot 做的事情和 SpringDoc

    最佳答案

    根据从 Flask 迁移到 FastAPI 的建议,我试了一下并重写了 Flask-Example的问题。源代码也可在 GitHub 上获得.
    该项目的结构几乎相同,但提供了一些附加功能(例如 CORS 中间件):
    enter image description here
    域的模型略有不同,扩展了BaseModel来自 Pydantic .

    # author.py
    from pydantic import BaseModel
    
    
    class Author(BaseModel):
        id: str
        name: str
    
    # book.py
    from pydantic import BaseModel
    
    
    class Book(BaseModel):
        id: str
        name: str
    
    使用 FastAPI 相当于 flask 蓝图 APIRouter .
    以下是作者的两个 Controller
    # 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
    
    和书
    # 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
    
    需要注意的是,由于 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
    
    生成的 OpenAPI 文档可在端点访问 /openapi.json而 UI(又名 Swagger UI,Redoc)可在 /docs 访问
    enter image description here
    /redoc enter image description here
    总而言之,这是自动生成的 JSON 格式的 OpenAPI v3 文档,可用于轻松生成其他语言的 API 客户端(例如使用 OpenAPI-Generator tools)。
    {
      "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"
              }
            }
          }
        }
      }
    }
    
    为了启动应用程序,我们还需要一个用于生产的 ASGI 服务器,例如 UvicornHypercorn .
    我使用了 Uvicorn,应用程序是使用以下命令启动的:
    uvicorn app:app --reload
    
    然后它可以在您机器的端口 8000 上使用。

    关于python - Flask:如何自动化 OpenAPI v3 文档?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67849806/

    相关文章:

    python - 根据图像调整边界框的大小

    Python Tkinter Tk 支持检查列表框?

    python - Python 会自动用 << 1 替换 * 2 吗?

    json - 我们如何使用 Flask-Admin 更新 HSTORE 字段?

    python - 如何在flask登录中实现localize_callback

    python - 如何扩展和填充黑白图像的第三个暗角

    python - 如何让easy_install在setup.py中执行自定义命令?

    python - 如何在 Python 中设计一个类?

    Python 写入文件使用不必要的存储?

    Apache + WSGI 运行 Flask,得到 Python ImportError : "cannot import name ..." or "No module named ..."