FastAPI中如何修复openapi_extra自定义Schema的引用解析错误?
使用Pydantic v1.10编写的FastAPI代码如下:
import uvicorn from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class Department(BaseModel): name: str address: str class Employee(BaseModel): first_name: str last_name: str department: Department @app.post( '/upload/', openapi_extra={ 'requestBody': { 'content': { 'application/json': { 'schema': Employee.schema(ref_template='#/components/schemas/{model}') } } } } ) async def create_employee(employee: Employee): return employee if __name__ == '__main__': uvicorn.run(app)
生成Schema时出现以下错误:
Resolver error at
paths./upload/.post.requestBody.content.application/json.schema.properties.department.$ref
Could not resolve reference: Could not resolve pointer:
/components/schemas/Department does not exist in document
注:采用此方式构建Schema是因为正在开发网关服务,需将请求转发,但仍需在Swagger中展示Schema。
错误原因
直接调用Employee.schema(ref_template='#/components/schemas/{model}')生成的Schema中,department字段会引用#/components/schemas/Department,但由于手动覆盖了requestBody的配置,FastAPI未自动将嵌套的Department模型注册到OpenAPI文档的components.schemas中,导致引用路径无法解析。
方法一:直接复用FastAPI自动注册的模型引用(推荐)
无需手动生成Schema,直接通过$ref引用FastAPI自动注册的模型即可。因为路由参数中已经声明了employee: Employee,FastAPI会自动将Employee及其嵌套的Department模型注册到OpenAPI组件中,只需在openapi_extra中指定引用路径:
import uvicorn from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class Department(BaseModel): name: str address: str class Employee(BaseModel): first_name: str last_name: str department: Department @app.post( '/upload/', openapi_extra={ 'requestBody': { 'content': { 'application/json': { 'schema': {'$ref': '#/components/schemas/Employee'} } } } } ) async def create_employee(employee: Employee): # 在此处添加请求转发逻辑 return employee if __name__ == '__main__': uvicorn.run(app)
方法二:手动注册模型到OpenAPI组件
如果需要完全手动控制Schema结构,可以通过自定义openapi函数,将嵌套模型的Schema手动添加到OpenAPI文档的组件中:
import uvicorn from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class Department(BaseModel): name: str address: str class Employee(BaseModel): first_name: str last_name: str department: Department def custom_openapi(): if app.openapi_schema: return app.openapi_schema # 生成基础OpenAPI Schema openapi_schema = app.openapi() # 手动添加模型Schema到组件 openapi_schema["components"]["schemas"]["Department"] = Department.schema() openapi_schema["components"]["schemas"]["Employee"] = Employee.schema(ref_template='#/components/schemas/{model}') app.openapi_schema = openapi_schema return app.openapi_schema # 替换默认的openapi生成函数 app.openapi = custom_openapi @app.post( '/upload/', openapi_extra={ 'requestBody': { 'content': { 'application/json': { 'schema': Employee.schema(ref_template='#/components/schemas/{model}') } } } } ) async def create_employee(employee: Employee): # 在此处添加请求转发逻辑 return employee if __name__ == '__main__': uvicorn.run(app)
内容的提问来源于stack exchange,提问作者Альберт Александров

