Karol Zlot
Karol Zlot

Reputation: 4065

How to immediately return uploaded file in FastAPI or Starlette?

I want to upload a file and in request and in response to this request I want to return the same file.

I would prefer to do this without saving file to disk. So I want to somehow return SpooledTemporaryFile content which is how FastAPI / Starlette stores in-memory uploaded file (with some smart disk caching).

I tried:

import uvicorn
from fastapi.responses import HTMLResponse, StreamingResponse
from fastapi import FastAPI, UploadFile

app = FastAPI()


@app.get("/", response_class=HTMLResponse)
async def upload_form():

    return HTMLResponse("""
<form action="/upload/" method="post" enctype="multipart/form-data">
  Choose file:
  <input type="file" name="file" id="file">
  <input type="submit" value="Send file" name="submit">
    """)


@app.post("/upload/", response_class=StreamingResponse)
async def upload(file: UploadFile):

    return StreamingResponse(file.file)


if __name__ == "__main__":
    uvicorn.run("main:app")

But it doesn't work. When I upload a file, server crashes with an error:

TypeError: 'SpooledTemporaryFile' object is not an iterator

This question is similar to: https://www.reddit.com/r/FastAPI/comments/kxuukb/spooledfile_as_streamingresponse/


It may be related to: https://bugs.python.org/issue26175

Upvotes: 0

Views: 1485

Answers (1)

Karol Zlot
Karol Zlot

Reputation: 4065

It turned out Response is needed for this use case instead of StreamingResponse:

import uvicorn
from fastapi.responses import HTMLResponse, Response
from fastapi import FastAPI, UploadFile
app = FastAPI()


@app.get("/", response_class=HTMLResponse)
async def upload_form():

    return HTMLResponse("""
<form action="/upload/" method="post" enctype="multipart/form-data">
  Choose file:
  <input type="file" name="file" id="file">
  <input type="submit" value="Send file" name="submit">
    """)


@app.post("/upload/", response_class=Response)
async def upload(file: UploadFile):

    return Response(file.file.read(), media_type=file.content_type)


if __name__ == "__main__":
    uvicorn.run("main_stack:app")

Upvotes: 0

Related Questions