Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create an OpenAPI schema for an UploadFile in FastAPI?

FastAPI automatically generates a schema in the OpenAPI spec for UploadFile parameters.

For example, this code:

from fastapi import FastAPI, File, UploadFile

app = FastAPI()


@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile = File(..., description="The file")):
    return {"filename": file.filename}

will generate this schema under components:schemas in the OpenAPI spec:

{
    "Body_create_upload_file_uploadfile__post": {
        "title": "Body_create_upload_file_uploadfile__post",
        "required":["file"],
        "type":"object",
        "properties":{
            "file": {"title": "File", "type": "string", "description": "The file","format":"binary"}
        }
    }
}

How can I explicitly specify the schema for UploadFiles (or at least its name)?

I have read FastAPIs docs and searched the issue tracker but found nothing.

like image 345
Stefan Scherfke Avatar asked Mar 19 '20 21:03

Stefan Scherfke


2 Answers

I answered this over on FastAPI#1442, but just in case someone else stumbles upon this question here is a copy-and-paste from the post linked above:

After some investigation this is possible, but it requires some monkey patching. Using the example given here, the solution looks like so:

from fastapi import FastAPI, File, UploadFile
from typing import Callable

app = FastAPI()

@app.post("/files/")
async def create_file(file: bytes = File(...)):
    return {"file_size": len(file)}

@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile = File(...)):
    return {"filename": file.filename}

def update_schema_name(app: FastAPI, function: Callable, name: str) -> None:
    """
    Updates the Pydantic schema name for a FastAPI function that takes
    in a fastapi.UploadFile = File(...) or bytes = File(...).

    This is a known issue that was reported on FastAPI#1442 in which
    the schema for file upload routes were auto-generated with no
    customization options. This renames the auto-generated schema to
    something more useful and clear.

    Args:
        app: The FastAPI application to modify.
        function: The function object to modify.
        name: The new name of the schema.
    """
    for route in app.routes:
        if route.endpoint is function:
            route.body_field.type_.__name__ = name
            break

update_schema_name(app, create_file, "CreateFileSchema")
update_schema_name(app, create_upload_file, "CreateUploadSchema")

Screen Shot 2021-03-02 at 12 52 04 AM

like image 55
Felipe Avatar answered Oct 04 '22 13:10

Felipe


You can edit the OpenAPI schema itself. I prefer to just move these schemas to the path (since they are unique to each path anyway):

from fastapi import FastAPI, File, UploadFile
from fastapi.openapi.utils import get_openapi


app = FastAPI()


@app.post("/uploadfile/")
async def create_upload_file(file1: UploadFile = File(...), file2: UploadFile = File(...)):
    pass


def custom_openapi():
    if app.openapi_schema:
        return app.openapi_schema
    openapi_schema = get_openapi(
        title="Custom title",
        version="2.5.0",
        description="This is a very custom OpenAPI schema",
        routes=app.routes,
    )
    # Move autogenerated Body_ schemas, see https://github.com/tiangolo/fastapi/issues/1442
    for path in openapi_schema["paths"].values():
        for method_data in path.values():
            if "requestBody" in method_data:
                for content_type, content in method_data["requestBody"]["content"].items():
                    if content_type == "multipart/form-data":
                        schema_name = content["schema"]["$ref"].lstrip("#/components/schemas/")
                        schema_data = openapi_schema["components"]["schemas"].pop(schema_name)
                        content["schema"] = schema_data
    app.openapi_schema = openapi_schema
    return app.openapi_schema

app.openapi = custom_openapi
like image 26
LoveToCode Avatar answered Oct 04 '22 12:10

LoveToCode