Skip to content

Technical — Minio Uploader

RAGA's file upload to MinIO service, built on Python + FastAPI. Accepts image and document files via multipart form, validates MIME type and size, then streams them directly to MinIO object storage. The public file URL is returned as soon as the upload finishes. Used by api-tarantula as the storage backend for files uploaded by users.

Note: this service does not use Infisical — configuration is read directly from a .env file via python-dotenv.

Repository

KeyValue
Git Remotehttps://git.tlab.co.id/tarantula/service/minio-uploader.git
Active Branchmain
bash
git clone https://git.tlab.co.id/tarantula/service/minio-uploader.git
cd minio-uploader

Tech Stack

LayerTechnology
RuntimePython 3.11
FrameworkFastAPI + uvicorn
Storage Clientminio Python SDK
Configpython-dotenv (.env file directly, no Infisical)
Uploadpython-multipart (multipart/form-data)
ContainerizationDocker (python:3.11-slim)

Folder Structure

minio-uploader/
├── app.py               # FastAPI app + all upload logic
├── requirements.txt
├── .env.sample
├── Dockerfile            # Dev/local image (python:3.11-slim)
├── Dockerfile.stag       # Staging/production image (python:3.11, used by CI deploy)
└── docker-compose.yml   # Dev setup: MinIO + minio-uploader

Environment Variables

All configuration is read from a .env file via python-dotenv. No Infisical.

.env File

bash
MINIO_ENDPOINT=minio:9000
MINIO_ACCESS_KEY=
MINIO_SECRET_KEY=
MINIO_BUCKET=tarantula-api
MINIO_DOMAIN=https://s3.ziwardingai.xyz
VariableDefaultDescription
MINIO_ENDPOINTminio:9000MinIO server host:port (without http://)
MINIO_ACCESS_KEYMinIO access key (required)
MINIO_SECRET_KEYMinIO secret key (required)
MINIO_BUCKETtarantula (code default) / tarantula-api (in .env.sample)Target bucket name; created automatically if it doesn't exist
MINIO_DOMAINMinIO's public base URL (e.g. https://s3.ziwardingai.xyz); used to build the response URL (required)

The MinIO connection is created with secure=False — make sure the endpoint is on an internal network or already reverse-proxied with TLS in front of it.

Endpoint

MethodPathDescription
POST/upload/Upload images and/or documents to MinIO

POST /upload/

Content-Type: multipart/form-data

images       (List[UploadFile], optional) — image / video files
files        (List[UploadFile], optional) — document files
folder_path  (str, query param, optional) — root folder in MinIO

At least one of images or files must be provided.

200 OK Response:

json
{
  "images": [
    "https://s3.ziwardingai.xyz/tarantula-api/my-project/document.png"
  ],
  "files": [
    "https://s3.ziwardingai.xyz/tarantula-api/my-project/report.pdf"
  ]
}

Folder Path Logic

ConditionImages PathFiles Path
folder_path not providedupload-api-service/jajal/images/upload-api-service/jajal/files/
folder_path=my-projectmy-project/my-project/

When folder_path is provided, images and files are stored in the same folder (no images/ or files/ subfolder is added). Final object name: {folder}/{filename}.

File Validation

Allowed Types

Images (Content-Type):

MIME TypeExtension
image/png.png
image/jpeg.jpg, .jpeg
image/jpg.jpg
video/mp4.mp4
video/quicktime.mov

Files (Content-Type):

MIME TypeExtension
application/pdf.pdf
application/vnd.openxmlformats-officedocument.wordprocessingml.document.docx
text/plain.txt
application/vnd.openxmlformats-officedocument.presentationml.presentation.pptx
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.xlsx
text/csv.csv
application/json.json

Size Limit

  • Maximum 100 MB per file
  • 400 Bad Request if the limit is exceeded or the MIME type is invalid

Upload Flow

The upload is streamed (upload_to_minio_direct) — the file is never fully read into memory; only its size is checked (seek) before it's streamed directly to MinIO via put_object.

Docker

docker-compose.yml (dev)

yaml
services:
  minio:
    image: minio/minio
    environment:
      MINIO_ROOT_USER: minioAccessKey
      MINIO_ROOT_PASSWORD: minioSecretKey
    volumes:
      - minio_data:/data
    ports:
      - "9000:9000"   # S3 API
      - "9090:9001"   # MinIO Console
    command: ["server", "--console-address", ":9001", "/data"]

  minio-uploader:
    container_name: minio-uploader
    build: .
    volumes:
      - .:/app
    env_file: .env
    ports:
      - "8000:8000"
    depends_on:
      - minio

Build & Run

bash
# Install dependencies
pip install -r requirements.txt

# Run development (make sure .env is filled in)
uvicorn app:app --reload --port 8000

# Docker Compose (dev — includes local MinIO)
docker compose up --build

# Standalone Docker build & run
docker build -t minio-uploader .
docker run -p 8000:8000 \
  -e MINIO_ENDPOINT=minio:9000 \
  -e MINIO_ACCESS_KEY=your-access-key \
  -e MINIO_SECRET_KEY=your-secret-key \
  -e MINIO_BUCKET=tarantula-api \
  -e MINIO_DOMAIN=https://s3.ziwardingai.xyz \
  minio-uploader