Flask: how to automate OpenAPI v3 documentation?

Solution 1
# 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
# 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
# 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": "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"
          }
        }
      }
    }
  }
}
uvicorn app:app --reload
Solution 2
from swagger_gen.lib.wrappers import swagger_metadata
from swagger_gen.lib.security import BearerAuth
from swagger_gen.swagger import Swagger
from flask import Flask, request

app = Flask(__name__)


@app.route('/api/hello/say', methods=['GET'])
@swagger_metadata(
    summary='Sample endpoint',
    description='This is a sample endpoint')
def test():
    return {'message': 'hello world!'}


swagger = Swagger(
    app=app,
    title='app')

swagger.configure()

if __name__ == '__main__':
    app.run(debug=True, port='5000')