Skip to content

Repository files navigation

CloudShare REST API

PythonFastAPIStreamlitSQLiteSQLAlchemy

A modern, full-stack cloud storage and media sharing platform built with FastAPI and Streamlit. Upload images and videos, share them with the world, and manage your content — all powered by cloud infrastructure.


📸 Screenshots

image
imageimage

Features

  • JWT Authentication — Secure register/login flow using FastAPI Users with bcrypt + argon2 password hashing
  • Media Uploads — Support for images (PNG, JPG, JPEG) and videos (MP4, AVI, MOV, MKV, WEBM)
  • Cloud Storage — Files are uploaded directly to ImageKit.io for optimized delivery
  • Social Feed — Browse all posts from every user, sorted by newest first
  • Caption Overlays — ImageKit's transformation API renders captions directly on images
  • Post Ownership — Users can only delete their own posts; enforced at the API level
  • Async Backend — Fully async FastAPI + aiosqlite stack for high throughput
  • Dark UI — Polished Streamlit interface with a custom dark theme

Tech Stack

Backend

LibraryPurpose
FastAPIHigh-performance async web framework
FastAPI UsersAuth, JWT, registration, password hashing
SQLAlchemy 2.0ORM + async session management
aiosqliteAsync SQLite driver
UvicornASGI server with hot-reload
ImageKit Python SDKCloud media upload and URL transformations
python-dotenvEnvironment variable management

Frontend

LibraryPurpose
StreamlitRapid Python UI framework
RequestsHTTP client for calling the FastAPI backend

Database

ComponentDetails
SQLiteLightweight, file-based, zero-config
aiosqliteNon-blocking async access
SQLAlchemy ORMDeclarative models, relationship management

Why SQLAlchemy?

SQLAlchemy is the gold standard ORM for Python, and using it here — even with SQLite — was a deliberate choice for several reasons:

1. Async-first with SQLAlchemy 2.0 SQLAlchemy 2.0 introduced a fully async API (AsyncSession, create_async_engine). Combined with aiosqlite, all database operations are non-blocking, which keeps FastAPI's event loop free and maximises concurrency.

2. Declarative models keep schema close to code Defining User and Post as Python classes (via DeclarativeBase) means the database schema is version-controlled alongside the application code. There's no separate migration file to remember to keep in sync.

classPost(Base):
__tablename__="posts"id=Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
user_id=Column(UUID(as_uuid=True), ForeignKey("user.id"), nullable=False)
caption=Column(Text)
url=Column(String, nullable=False)
...

3. Relationships with zero raw SQL SQLAlchemy's relationship() directive wires Post → User bidirectionally. Fetching a post's author, or all posts belonging to a user, happens through Python attribute access rather than hand-written JOINs.

4. FastAPI Users integrationFastAPI Users ships a first-class SQLAlchemy adapter (fastapi-users-db-sqlalchemy). Using SQLAlchemy means the full auth stack — registration, JWT login, password reset — is handled by battle-tested library code instead of custom logic.

5. Easy upgrade path Swapping SQLite for PostgreSQL in production requires changing exactly one line:

# DevelopmentDATABASE_URL="sqlite+aiosqlite:///./test.db"# ProductionDATABASE_URL="postgresql+asyncpg://user:pass@host/db"

The rest of the application is untouched.


Project Structure

cloudshare-rest-api/
├── app/
│ ├── __init__.py
│ ├── app.py # FastAPI app, route definitions
│ ├── db.py # SQLAlchemy models, engine, session factory
│ ├── schemas.py # Pydantic schemas (request/response validation)
│ ├── users.py # JWT strategy, auth backend, UserManager
│ └── images.py # ImageKit SDK initialisation
├── frontend.py # Streamlit UI
├── main.py # Uvicorn entry point
├── pyproject.toml # Project metadata & dependencies
├── uv.lock # Locked dependency tree
└── .gitignore

Database Schema

CREATETABLE "user" (
id UUID PRIMARY KEY,
email VARCHARNOT NULL UNIQUE,
hashed_password VARCHARNOT NULL,
is_active BOOLEAN DEFAULT TRUE,
is_superuser BOOLEAN DEFAULT FALSE,
is_verified BOOLEAN DEFAULT FALSE
);
CREATETABLEposts (
id UUID PRIMARY KEY,
user_id UUID REFERENCES"user"(id) NOT NULL,
caption TEXT,
url VARCHARNOT NULL, -- ImageKit CDN URL
file_type VARCHARNOT NULL, -- 'image' or 'video'
file_name VARCHARNOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

Prerequisites


⚙️ Installation

1. Clone the repository

git clone https://github.com/yourusername/cloudshare-rest-api.git
cd cloudshare-rest-api

2. Install dependencies

# Using pip
pip install -e .# Using uv (faster)
uv pip install -e .

3. Set your ImageKit credentials

Create a .env file in the project root:

IMAGEKIT_PRIVATE_KEY=your_private_key_hereIMAGEKIT_PUBLIC_KEY=your_public_key_hereIMAGEKIT_URL=https://ik.imagekit.io/your_endpoint

Get your credentials from ImageKit Dashboard → Settings → API Keys.


Running the App

Start the backend (FastAPI)

python main.py

The API is now live at http://localhost:8000

Start the frontend (Streamlit) — in a second terminal

streamlit run frontend.py

The UI opens at http://localhost:8501

Browse the auto-generated API docs

InterfaceURL
Swagger UIhttp://localhost:8000/docs
ReDochttp://localhost:8000/redoc

API Reference

Authentication

MethodEndpointDescription
POST/auth/registerCreate a new account
POST/auth/jwt/loginLogin and receive a JWT
POST/auth/jwt/logoutInvalidate the current session
GET/users/meReturn the authenticated user's profile

Posts

MethodEndpointDescription
POST/uploadUpload a media file and create a post
GET/feedReturn all posts, newest first
DELETE/posts/{post_id}Delete a post (owner only)

Authentication Flow

User registers → Password hashed (argon2/bcrypt) → Stored in DB
↓
User logs in → JWT issued (1 hour lifetime)
↓
Frontend stores token in Streamlit session_state
↓
All API requests include: Authorization: Bearer <token>
↓
Backend validates token → Resolves current_active_user dependency

The JWT secret lives in app/users.py. Change this to a strong random value before deploying to production.


ImageKit Integration

Uploaded files are streamed to ImageKit's CDN via the Python SDK. The returned CDN URL is saved to the database and served directly to clients — the application server never stores binary files.

Caption overlays are applied using ImageKit's URL-based transformation API:

/tr:l-text,ie-<base64_caption>,ly-N20,fs-100,co-white,bg-000000A0,l-end/

This encodes the caption as base64, overlays it at the bottom of the image with a semi-transparent background, and delivers it as a single optimised request.


🔧 Example cURL Requests

Register

curl -X POST http://localhost:8000/auth/register \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "password": "secret123"}'

Login

curl -X POST http://localhost:8000/auth/jwt/login \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=you@example.com&password=secret123"

Get feed

curl http://localhost:8000/feed \
-H "Authorization: Bearer YOUR_TOKEN_HERE"

Upload a post

curl -X POST http://localhost:8000/upload \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-F "file=@photo.jpg" \
-F "caption=Hello world!"

Troubleshooting

ProblemFix
Connection refused on port 8000Run python main.py first
Upload failed errorCheck that ImageKit credentials in .env are correct
Module not foundRun pip install -e . first
JWT token expiredLog out and log back in to receive a fresh token
Database not createdIt auto-creates on first startup; ensure write permissions in the project directory

About

Asynchronous REST API and Streamlit frontend for cloud media sharing. Built with FastAPI, SQLite (aiosqlite), and ImageKit.io.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages