Received & return a file from in-memory buffer using FastAPI
FastAPI is fast becoming the go-to choice to write APIs using Python mostly due to its asynchronous nature.
FastAPI by default will use
JSONResponse method to return responses, however, it has the ability to return several custom responses including
FileResponse. However, both of these messages returns files that are saved on the disk and requires a
E.g. from FastAPI Documentation,
from fastapi import FastAPI from fastapi.responses import FileResponse file_path = "sample-file.mp4" app = FastAPI() @app.get("/", response_class=FileResponse) async def main(): return file_path
So what if you wanted to send a file that is currently in the memory buffer, directly without the additional step of saving it on the disk?
Why simply using StreamingResponse is not enough?
The right way of sending a file from memory is by using
StreamingResponse requires an iterator object, e.g.
from fastapi import FastAPI from fastapi.responses import StreamingResponse some_file_path = "large-video-file.mp4" app = FastAPI() @app.get("/") def main(): def iterfile(): with open(some_file_path, mode="rb") as file_like: yield from file_like return StreamingResponse(iterfile(), media_type="video/mp4")
But in reality the files e.g. images, etc. that you work with will rarely be an iterator object. Thus you are swapping one workaround with another workaround.
Using StreamingResponse correctly
Instead what we will do is, 1. Receive the image directly in memory 2. Apply a
blur PIL filter to the image method to the image 3. Return the image directly without saving
from fastapi import FastAPI, File, UploadFile from fastapi.responses import StreamingResponse from io import BytesIO app = FastAPI() @app.post("/") def image_filter(img: UploadFile = File(...)): original_image = Image.open(img.file) original_image = original_image.filter(ImageFilter.BLUR) filtered_image = BytesIO() original_image.save(filtered_image, "JPEG") filtered_image.seek(0) return StreamingResponse(filtered_image, media_type="image/jpeg")
Testing the API
Save the above code in a file named app.py
You need to install the following libraries for this to work
pip install fastapi pip install "uvicorn[standard]" pip install Pillow pip install python-multipart
Then fire up the FastAPI app by running
uvicorn app:app --reload
This should start the app on
127.0.0.1/8000 as shown below
Open the swaggerUI using any browser by openign the link
127.0.0.1/8000/docs, then click on try it out, then choose a image from and press Execute.
After that if you scroll below you should see a blurred image.
An example of before and after is shown below, (but really this is just an excuse to show you a cat pic)