当前位置: 首页 > 知识库问答 >
问题:

OpenAPI缺少FastAPI应用程序中某些Pydantic模型的模式

苏华藏
2023-03-14

我正在构建一个FastAPI应用程序,它有很多Pydantic模型。尽管应用程序运行良好,但正如所料,OpenAPI (Swagger UI)文档并没有在< code>Schemas部分显示所有这些模型的模式。

下面是pydantic<code>模式的内容。py</code>

import socket
from datetime import datetime
from enum import Enum
from typing import Any, Dict, List, Optional, Set, Union

from pydantic import BaseModel, Field, validator
from typing_extensions import Literal

ResponseData = Union[List[Any], Dict[str, Any], BaseModel]


# Not visible in Swagger UI
class PageIn(BaseModel):
    page_size: int = Field(default=100, gt=0)
    num_pages: int = Field(default=1, gt=0, exclude=True)
    start_page: int = Field(default=1, gt=0, exclude=True)

# visible under schemas on Swagger UI
class PageOut(PageIn):
    total_records: int = 0
    total_pages: int = 0
    current_page: int = 1

    class Config:  # pragma: no cover
        @staticmethod
        def schema_extra(schema, model) -> None:
            schema.get("properties").pop("num_pages")
            schema.get("properties").pop("start_page")


# Not visible in Swagger UI
class BaseResponse(BaseModel):
    host_: str = Field(default_factory=socket.gethostname)
    message: Optional[str]


# Not visible in Swagger UI
class APIResponse(BaseResponse):
    count: int = 0
    location: Optional[str]
    page: Optional[PageOut]
    data: ResponseData


# Not visible in Swagger UI
class ErrorResponse(BaseResponse):
    error: str


# visible under schemas on Swagger UI
class BaseFaultMap(BaseModel):
    detection_system: Optional[str] = Field("", example="obhc")
    fault_type: Optional[str] = Field("", example="disk")
    team: Optional[str] = Field("", example="dctechs")
    description: Optional[str] = Field(
        "",
        example="Hardware raid controller disk failure found. "
        "Operation can continue normally,"
        "but risk of data loss exist",
    )



# Not visible in Swagger UI
class FaultQueryParams(BaseModel):
    f_id: Optional[int] = Field(None, description="id for the host", example=12345, title="Fault ID")
    hostname: Optional[str]
    status: Literal["open", "closed", "all"] = Field("open")
    created_by: Optional[str]
    environment: Optional[str]
    team: Optional[str]
    fault_type: Optional[str]
    detection_system: Optional[str]
    inops_filters: Optional[str] = Field(None)
    date_filter: Optional[str] = Field("",)
    sort_by: Optional[str] = Field("created",)
    sort_order: Literal["asc", "desc"] = Field("desc")

所有这些模型实际上都在FastAPI路径中用于验证请求体。< code>FaultQueryParams是一个自定义模型,我用它来验证请求查询参数,用法如下:

query_args:FaultQueryParams=Depends()

其余模型与Body字段一起使用。我无法理解为什么只有一些模型Schemas部分中不可见,而其他模型则不可见。

关于< code>FaultQueryParams,我注意到的另一件事是,描述和示例不会显示在路径endpoint上,即使它们是在模型中定义的。

编辑1:

我深入研究并意识到,在swagger UI中不可见的所有模型都不是直接用于路径操作的模型,也就是说,这些模型不是用作response_modelBody类型,而是间接使用的助手模型。因此,FastAPI似乎没有为这些模型生成模式。

上述语句的一个例外是query_args:FaultQueryParams=Depends(),它直接用于路径操作,以将endpoint的查询params映射到自定义模型。这是一个问题,因为swagger没有从该模型的字段中识别元参数,如<code>title</code>、<code>description</code>、<code>example</ccode>

有没有办法欺骗 FastAPI 为自定义模型 FaultQueryParams 生成架构,就像它为 BodyQuery 等生成架构一样?

共有2个答案

高增
2023-03-14

感谢@Chris提供的指针,这些指针最终导致我使用数据类来批量定义查询参数,而且它工作得很好。

@dataclass
class FaultQueryParams1:
    f_id: Optional[int] = Query(None, description="id for the host", example=55555)
    hostname: Optional[str] = Query(None, example="test-host1.domain.com")
    status: Literal["open", "closed", "all"] = Query(
        None, description="fetch open/closed or all records", example="all"
    )
    created_by: Optional[str] = Query(
        None,
        description="fetch records created by particular user",
        example="user-id",
    )
艾意蕴
2023-03-14

FastAPI将为用作请求主体或响应模型的模型生成模式。当声明query_args:FaultQueryParams=Depends()(使用Depends)时,endpoint不需要请求体,而是需要查询parameters;因此,FaultQueryParams不会包含在OpenAPI文档的模式中。

要添加其他模式,可以扩展/修改OpenAPI模式。下面给出了示例(请确保在定义了所有路由之后,即在代码末尾添加用于修改模式的代码)。

class FaultQueryParams(BaseModel):
    f_id: Optional[int] = Field(None, description="id for the host", example=12345, title="Fault ID")
    hostname: Optional[str]
    status: Literal["open", "closed", "all"] = Field("open")
    ...
    
@app.post('/predict')
def predict(query_args: FaultQueryParams = Depends()):
    return query_args

def get_extra_schemas():
    return {
              "FaultQueryParams": {
                "title": "FaultQueryParams",
                "type": "object",
                "properties": {
                  "f_id": {
                    "title": "Fault ID",
                    "type": "integer",
                    "description": "id for the host",
                    "example": 12345
                  },
                  "hostname": {
                    "title": "Hostname",
                    "type": "string"
                  },
                  "status": {
                    "title": "Status",
                    "enum": [
                      "open",
                      "closed",
                      "all"
                    ],
                    "type": "string",
                    "default": "open"
                  },
                   ...
                }
              }
            }

from fastapi.openapi.utils import get_openapi

def custom_openapi():
    if app.openapi_schema:
        return app.openapi_schema
    openapi_schema = get_openapi(
        title="FastAPI",
        version="1.0.0",
        description="This is a custom OpenAPI schema",
        routes=app.routes,
    )
    new_schemas = openapi_schema["components"]["schemas"]
    new_schemas.update(get_extra_schemas())
    openapi_schema["components"]["schemas"] = new_schemas
    
    app.openapi_schema = openapi_schema
    return app.openapi_schema


app.openapi = custom_openapi

您可以让 FastAPI 为您执行此操作,方法是将该模型用作请求正文或响应模型,方法是在代码中添加终端节点(获取架构后随后会删除该终结点),例如:

@app.post('/predict') 
def predict(query_args: FaultQueryParams):
    return query_args

然后,可以在 http://127.0.0.1:8000/openapi.json 获取生成的 JSON 架构,如文档中所述。从那里,可以将模型的架构复制并粘贴到代码中并直接使用它(如上面的 get_extra_schema() 方法所示),也可以将其保存到文件并从文件中加载 JSON 数据,如下所示:

import json
...

new_schemas = openapi_schema["components"]["schemas"]

with open('extra_schemas.json') as f:    
    extra_schemas = json.load(f)
    
new_schemas.update(extra_schemas)   
openapi_schema["components"]["schemas"] = new_schemas

...

要为查询参数声明元数据,如< code>description 、< code>example等,您应该用< code>Query而不是< code>Field来定义参数,因为您不能对Pydantic模型这样做,所以您可以声明一个自定义依赖类,如下所述:

from fastapi import FastAPI, Query, Depends
from typing import Optional

class FaultQueryParams:
    def __init__(
        self,
        f_id: Optional[int] = Query(None, description="id for the host", example=12345)

    ):
        self.f_id = f_id

app = FastAPI()

@app.post('/predict')
def predict(query_args: FaultQueryParams = Depends()):
    return query_args

上面的代码可以用< code>@dataclass装饰器重写,如下所示:

from fastapi import FastAPI, Query, Depends
from typing import Optional
from dataclasses import dataclass

@dataclass
class FaultQueryParams:
    f_id: Optional[int] = Query(None, description="id for the host", example=12345)

app = FastAPI()

@app.post('/predict')
def predict(query_args: FaultQueryParams = Depends()):
    return query_args
 类似资料:
  • 我有两个应用程序:同事和服务,每个都有自己的模型 在coworkers models.py中,我可以“从services.models导入服务”。 当我尝试在services models.py中“from coworkers.models import Status”时,会收到以下错误消息: 回溯(最近一次调用):文件“/Users/lucas/Documents/projetos/cwk-ma

  • 当我启动模拟器时,我收到错误消息,因为 模拟器:PANIC:缺少“arm”CPU的模拟器引擎程序。 模拟器:进程已完成,退出代码为 1 Win 10 , Android Studio3.1.4 , AVD 联结 4 Api21

  • 在FastAPI中,我使用了SQLAlchemy和Pydanic返回数据 这种方式可以帮助我规范化返回的模型,但是我想要将所有api统一返回格式为{"code":0,"msg":"success","data":{...}},使原本返回模型中User的模型置于data中,方便前端管理。 我尝试了使用FastAPI中间件来实现,但是在swagger等文档中无法识别返回模型User;如果重新定义一个通

  • Maven JavaFx项目编译但从控制台运行时给出“缺少JavaFx应用程序类”错误消息 上面的方法是“创建一个新的主类,并调用扩展应用程序的类的主方法”。 然而,我仍然面临以下问题: 2.java--module-path“c:\program files\java\javafx-sdk-11.0.2\lib”--add-modules=javafx.controls,javafx.fxml,

  • 我正在使用Springdoc来记录我在Spring Boot中制作的REST API。我需要从Swagger UI的模式部分隐藏一些模型/模式,这些模型/模式只在应用编程接口内部使用,所以没有必要在模式部分显示它们。 这是我试图隐藏的模型之一: 上图所示模型的超类: 这些示例中的大多数注释都来自JPA或Lombok。需要明确的是:在Schemas部分不可见–我在这里包括它只是为了以防万一。 到目前

  • 我目前正在使用OpenJDK11和OpenJFX构建一个应用程序。它编译得很好,并启动,但没有标题栏,如果我单击靠近应用程序边缘,它注册为在它后面的任何窗口上的单击。 我正在使用IntelliJ IDEA,花了一段时间才弄清楚如何将OpenJFX与它一起使用。不管怎样,以下是系统的详细信息: 我运行的是初等OS5.0Juno(基于Ubuntu18.04,一切都是GTK)IntelliJ IDEA(