Skip to main content
If your application supports user-uploaded files (such as media uploads), you’ll need a storage solution separate from the application’s local filesystem. Sevalla’s object storage is ideal for securely storing and serving these files.

Configuration

Start by creating an object storage on Sevalla. Settings contains all the values needed for your storages settings. This example requires the following environment variables:
  • BUCKET_ENDPOINT
  • BUCKET_SECRET_KEY
  • BUCKET_ACCESS_KEY
  • BUCKET_NAME
The values for these environment variables can be found on the Sevalla object store Settings page. In the FastAPI project, the settings can be added to config.py.
# app/core/config.py
class Settings(BaseSettings):
    model_config = SettingsConfigDict(env_file=".env",)

    SQLALCHEMY_DATABASE_URI: str = ""
    BUCKET_ENDPOINT: str = ""
    BUCKET_ACCESS_KEY: str = ""
    BUCKET_SECRET_KEY: str = ""
    BUCKET_NAME: str = ""

Install

To upload files from FastAPI, install boto3. Sevalla’s object storage is S3-compatible, allowing the S3 client in boto3 to be used for interfacing with the object store on Sevalla.
pip install boto3
pip freeze > requirements.txt

Example

Create a client with a dependency function

Before you can upload or read files in your bucket, you need to create an S3 client. This client is used for all S3-related methods. For this example, a function is added to dependencies.py and used inside any route that requires the boto3 client.
# app/core/dependencies.py
import boto3 
from botocore.client import Config
from app.core.config import settings

def get_s3_client():
    return boto3.client(
        "s3",
        endpoint_url=settings.BUCKET_ENDPOINT,
        aws_access_key_id=settings.BUCKET_ACCESS_KEY,
        aws_secret_access_key=settings.BUCKET_SECRET_KEY,
        config=Config(signature_version='s3v4')
    )

Upload a file

One method you can use to upload files is to take a file object (with a .read() method) and pass it to the upload_fileobj method. This adds it to the provided bucket with the supplied filename. This file object can come from using the UploadFile type.
# app/main.py
from fastapi import FastAPI, Depends, UploadFile 
from app.core.config import settings
from app.core.dependencies import get_s3_client 

app = FastAPI()

@app.post("/") 
def upload(file: UploadFile, s3_client=Depends(get_s3_client)):
    s3_client.upload_fileobj(
        file.file, 
        settings.BUCKET_NAME, 
        file.filename
    )
    return {"filename": file.filename}

List files

The list_objects_v2 method returns all the files in the supplied bucket. If your bucket is private, pre-signed URLs can be created to grant access to a file for a limited period.
# app/main.py
...
@app.get("/") 
def files(s3_client=Depends(get_s3_client)):
    files = []
    response = s3_client.list_objects_v2(Bucket=settings.BUCKET_NAME)
    for item in response.get('Contents', []):
        files.append({"filename": item['Key'], "url": s3_client.generate_presigned_url(
            'get_object',
            Params={'Bucket': settings.BUCKET_NAME, 'Key': item['Key']},
            ExpiresIn=60,
        )})
    return {"files": files}