> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sevalla.com/llms.txt
> Use this file to discover all available pages before exploring further.

# FastAPI - Object Storage

> The guide explains how to set up object storage for your FastAPI application.

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](https://docs.sevalla.com/object-storage/overview) is ideal for securely storing and serving these files.

## Configuration

Start by [creating an object storage](https://docs.sevalla.com/object-storage/add-an-object-storage) on Sevalla. **Settings** contains all the values needed for your storages settings.

This example requires the following [environment variables](https://docs.sevalla.com/applications/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`.

```python theme={null}
# app/core/config.py
class Settings(BaseSettings):
    model_config = SettingsConfigDict(env_file=".env",)

    SQLALCHEMY_DATABASE_URI: str = ""
    BUCKET_ENDPOINT: str = "" # [!code ++:4]
    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.

```shellsession theme={null}
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.

```python theme={null}
# app/core/dependencies.py
import boto3 # [!code ++:12]
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.

```python theme={null}
# app/main.py
from fastapi import FastAPI, Depends, UploadFile # [!code ++]
from app.core.config import settings
from app.core.dependencies import get_s3_client # [!code ++]

app = FastAPI()

@app.post("/") # [!code ++:8]
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.

```python theme={null}
# app/main.py
...
@app.get("/") # [!code ++:11]
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}
```
