Search code examples
pythonpython-asynciofastapistarlette

How to delete the file after a `return FileResponse(file_path)`


I'm using FastAPI to receive an image, process it and then return the image as a FileResponse.

But the returned file is a temporary one that need to be deleted after the endpoint return it.

@app.post("/send")
async def send(imagem_base64: str = Form(...)):

    # Convert to a Pillow image
    image = base64_to_image(imagem_base64)

    temp_file = tempfile.mkstemp(suffix = '.jpeg')
    image.save(temp_file, dpi=(600, 600), format='JPEG', subsampling=0, quality=85)

    return FileResponse(temp_file)

    # I need to remove my file after return it
    os.remove(temp_file)

How can I delete the file after return it ?


Solution

  • You can delete a file in a background task, as it will run after the response is sent.

    import os
    import tempfile
    
    from fastapi import FastAPI
    from fastapi.responses import FileResponse
    
    from starlette.background import BackgroundTasks
    
    app = FastAPI()
    
    
    def remove_file(path: str) -> None:
        os.unlink(path)
    
    
    @app.post("/send")
    async def send(background_tasks: BackgroundTasks):
        fd, path = tempfile.mkstemp(suffix='.txt')
        with os.fdopen(fd, 'w') as f:
            f.write('TEST\n')
        background_tasks.add_task(remove_file, path)
        return FileResponse(path)
    

    Another approach is to use dependency with yield. The finally block code will be executed after the response is sent and even after all background tasks have been completed.

    import os
    import tempfile
    
    from fastapi import FastAPI, Depends
    from fastapi.responses import FileResponse
    
    
    app = FastAPI()
    
    
    def create_temp_file():
        fd, path = tempfile.mkstemp(suffix='.txt')
        with os.fdopen(fd, 'w') as f:
            f.write('TEST\n')
        try:
            yield path
        finally:
            os.unlink(path)
    
    
    @app.post("/send")
    async def send(file_path=Depends(create_temp_file)):
        return FileResponse(file_path)
    

    Note: mkstemp() returns a tuple with a file descriptor and a path.