Uploading files to Azure storage account using FastAPI

ยท

5 min read

I've been lately playing around a lot with MS Azure, the world's second most popular cloud platform right behind AWS (Amazon Web Services). Recently, I implemented file upload feature from my application directly to Azure Storage. In this post, I'd be briefing how I achieved the same in some detail.

First things first, to follow this post some familiarity with Python, FastAPI and cloud computing is assumed. You're also supposed to have a testing MS Azure account. With that out of the way let's get started.

We'd start with MS Azure. Please login into your Azure account and search for a resource called 'Storage Accounts'. Create a storage account. In Azure, we store files inside storage account containers. Name this storage account, let's assume for the sake of simplicity it is named 'Example-Storage'. Now, open this resource inside Azure portal, on the right side you should see the 'containers' option. Navigate to 'containers' option, create a new container and name it 'images'. You'd be asked to provide access level while creating this resource, choose Blob so that anonymous users would be able to access contents inside this container. We'd need some keys to save to direct our uploads to this Azure Storage Container. Select the 'Example-Storage' account and open it on Azure portal, on the right side you should see the option 'Access Keys' under Security + Networking. Click on it and copy the key and connection string, these values would be used in our web application later along with the container name.

Now, let's start building a simple back-end API in FastAPI with an end-point that would allow you to directly upload multi-media files like images to Azure Storage Accounts. We'd use a package called 'azure-storage-blob' for this. So, activate your virtual environment and install this package through the terminal.

pip install azure-storage-blob

Install other packages required for fast API and create a 'main.py' file with the following contents:-

from fastapi import FastAPI, Request, Form, UploadFile, File, Depends
from fastapi.exceptions import HTTPException
from azure.storage.blob import BlobServiceClient
import uvicorn
from sqlalchemy.orm import Session

storage_account_key = 'your-storage-account-secret-key'
storage_account_name = 'amitstore'
connection_string = 'your-storage-account-connection-string'
container_name = 'images'    

import db

app = FastAPI(title="Test Fast API",
    docs_url="/docs",
    version="0.0.1")

@app.get("/")
async def main(request: Request):
    return {
        'message': 'Upload to Azure Fast API Example'
    }

@app.post("/azure-photo")
async def create_upload_file(name: str = Form(...), file: UploadFile = File(...), database: Session = Depends(db.get_db)):
    pass

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

This is a basic template of fastAPI. It has a root end-point which simply displays a message, docs URL has been specified. This project is linked with a database hence I've imported db from the config file. I've also initialized some variables like storage_account_key, name, container name and the connection string. All these values would be required to connect our web app with the storage account we created earlier on the Azure portal. I also have an end-point called '/azure-upload', this is where we'd be testing the file upload feature through Postman. Postman is an easy-to-use API-testing client which is cross-platform and free to use to a certain limit.

@app.post("/azure-photo")
async def create_upload_file(name: str = Form(...), file: UploadFile = File(...), database: Session = Depends(db.get_db)):
    if not file:
        return {"message": "No upload file sent"}
    else:
        blob_service_client = BlobServiceClient.from_connection_string(connection_string)
        blob_client = blob_service_client.get_blob_client(container=container_name, blob=name)

        try:
            contents = file.file.read()
            file.file.seek(0)
            blob_client.upload_blob(contents)
        except Exception:
            raise HTTPException(status_code=500, detail='Something went wrong')
        finally:
            file.file.close()

        return {
            'message': 'File uploaded successfully to Azure Cloud'
        }

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

The above piece of code only contains the function that is responsible for uploading the file on Azure. I'd break this down into smaller pieces and try to make you understand what this does at the core. I've used BlobServiceClient class from the library to connect with Azure storage account using the connection string and key. I called the 'from_connection_string' method passing connection string as a parameter. It created a blob client for us to upload files to Azure.

Then, I called get_blob_client method on it and passed the container name and filename to it. Filename would have the name with which your files inside the container would be named on the Azure Storage Account. In reality, you can attach a timestamp to it to generate a unique filename in case you plan to upload multiple versions of the same file. File object here comes from the class 'UploadFile' from FastAPI which uses spooled file upload. You need to have python-multipart installed to use the file upload feature in fastAPI. Inside the try-catch block I've read all the contents of the spooled file object, reset the file read pointer and then called the 'upload_blob' function with contents which would execute file upload to Azure. In case of any exception, we'd through a 500 error from the end-point and prompt the user to try again. In case of a successful operation, we simply return a success message.

Time to test this with Postman now. Open Postman, and create a new form-data post request. You should have two fields 'name' and 'file'. Name would be what you want your file to be named on Azure and file would be the image file you'd test uploading using the end-point we created just now. Once you successfully manage to hit the API, you should see a dummy success message. Now, let's confirm that our file is indeed uploading on Azure.

Try logging in to your Azure account, go to the Azure Storage account named 'Example-Storage'. Navigate inside the 'images' container we created earlier and you should see the file you uploaded if everything went smoothly.

With this, we come to the end of this post. Here, we learned about uploading our multi-media files to Azure storage account containers in Python using a very simple back-end in FastAPI. See you in the next post, until then Happy Coding and keep on learning ๐Ÿ˜ƒ

ย