A framework for building serverless applications using S3 as a backend
Project description
S3verless ๐
S3verless is a Python framework that lets you build complete web applications using only Amazon S3 as your backend. No databases, no servers, no complicated infrastructure - just S3 and your Python code.
โ ๏ธ Alpha Software: S3verless is currently in early development (v0.1.0). The API may change between releases. Use in production at your own risk.
โจ Features
- ๐๏ธ S3 as a Database: Store all your data as JSON objects in S3
- ๐ Drop-in FastAPI Integration: Automatic REST API generation for your models
- ๐จ Admin Interface: Auto-generated admin panel for managing your data
- ๐ Advanced Querying: Filter, sort, paginate, and search your S3 data
- ๐ Built-in Auth: JWT-based authentication with users stored in S3
- ๐ฆ Zero Config: Works out of the box with sensible defaults
- ๐ Truly Serverless: Deploy to AWS Lambda or any container platform
- ๐ฐ Cost-Effective: Pay only for S3 storage and requests
๐ฏ Why S3verless?
Traditional web applications require multiple services:
- โ Database server (RDS, DynamoDB, MongoDB)
- โ File storage (S3)
- โ Cache layer (Redis, Memcached)
- โ Session storage
- โ Complex deployment and scaling
With S3verless:
- โ Everything in S3
- โ Infinite scalability built-in
- โ Simple deployment
- โ Minimal operational overhead
- โ Perfect for MVPs, prototypes, and small to medium applications
๐ Quick Start
Installation
# Using uv (recommended)
uv pip install s3verless
# Or using pip
pip install s3verless
Create Your First Model
from s3verless import BaseS3Model
from pydantic import Field
class Product(BaseS3Model):
name: str = Field(..., min_length=1)
price: float = Field(..., gt=0)
description: str = ""
in_stock: bool = True
# That's it! S3verless automatically creates:
# - POST /products
# - GET /products
# - GET /products/{id}
# - PUT /products/{id}
# - DELETE /products/{id}
# - GET /products/search
# - Admin interface at /admin
Create Your App
from s3verless import create_s3verless_app
# Create the FastAPI app with S3 backend
app = create_s3verless_app(
title="My S3 Store",
model_packages=["models"], # Where your models live
enable_admin=True,
)
# Run with any ASGI server
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
Configure S3
Create a .env file:
AWS_ACCESS_KEY_ID=your-key
AWS_SECRET_ACCESS_KEY=your-secret
AWS_BUCKET_NAME=my-app-bucket
AWS_DEFAULT_REGION=us-east-1
# For local development with LocalStack
AWS_URL=http://localhost:4566
๐ Advanced Usage
Custom API Configuration
class Product(BaseS3Model):
# Customize API behavior
_plural_name = "products" # API endpoint name
_enable_api = True # Auto-generate CRUD endpoints
_enable_admin = True # Show in admin interface
_indexes = ["category", "price"] # Fields to index
_unique_fields = ["sku"] # Enforce uniqueness
name: str
sku: str
category: str
price: float
Advanced Queries
from s3verless import get_s3_client, query
async def find_products():
s3 = get_s3_client()
# Filter and sort
products = await query(Product, s3, "my-bucket").filter(
category="electronics",
price__lt=1000,
in_stock=True
).order_by("-created_at").limit(10).all()
# Pagination
page = await query(Product, s3, "my-bucket").paginate(
page=1,
page_size=20
)
# Complex queries
results = await query(Product, s3, "my-bucket").filter(
name__contains="iPhone"
).exclude(
price__gt=1500
).all()
Relationships
import uuid
class Order(BaseS3Model):
customer_id: uuid.UUID
items: list[dict] # Embedded items
total: float
async def get_customer(self, s3_client):
"""Fetch related customer."""
return await query(Customer, s3_client, "bucket").get(
id=self.customer_id
)
Hooks and Events
from s3verless.core.registry import add_model_hook
async def send_welcome_email(user):
print(f"Welcome {user.email}!")
# Register a post-creation hook
add_model_hook("User", "post_create", send_welcome_email)
๐ Authentication & Authorization
S3verless includes built-in JWT-based authentication with users stored in S3, plus automatic ownership checks and admin roles.
Basic Authentication
Simple JWT token authentication:
from s3verless.auth.service import S3AuthService
from s3verless.core.settings import S3verlessSettings
settings = S3verlessSettings()
auth_service = S3AuthService(settings)
# Register a new user
user = await auth_service.create_user(
s3_client=s3_client,
username="john",
email="john@example.com",
password="SecurePass123!",
full_name="John Doe"
)
# Authenticate and get JWT token
authenticated_user = await auth_service.authenticate_user(
s3_client=s3_client,
username="john",
password="SecurePass123!"
)
# Create access token
token = auth_service.create_access_token(
data={"sub": authenticated_user.username}
)
Protected Routes
from fastapi import Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
async def get_current_user(token: str = Depends(oauth2_scheme)):
try:
payload = auth_service.decode_token(token)
username = payload.get("sub")
user = await auth_service.get_user_by_username(s3_client, username)
if not user:
raise HTTPException(status_code=401)
return user
except Exception:
raise HTTPException(status_code=401)
@app.get("/protected")
async def protected_route(user = Depends(get_current_user)):
return {"message": f"Hello {user.username}"}
Current Limitations
The authentication system uses a single global secret key for signing all JWT tokens:
- โ Simple and stateless (standard JWT pattern)
- โ No database lookups for token validation
- โ Works great for most use cases
- โ ๏ธ Changing the secret invalidates ALL user tokens
- โ ๏ธ Cannot revoke individual user tokens (tokens valid until expiry)
- โ ๏ธ No per-user token invalidation (e.g., after password change)
For most applications, this is acceptable. See the Future Work section for planned improvements.
Security Best Practices:
- Use a strong, random
SECRET_KEY(32+ characters) - Keep tokens short-lived (15-30 minutes recommended)
- Use HTTPS in production
- Store the secret key securely (environment variables, AWS Secrets Manager)
- Consider implementing token refresh for better UX
See the auth example for a complete implementation.
Automatic Ownership & Admin Roles
Protect resources with automatic ownership checks and admin bypass:
class Post(BaseS3Model):
_require_ownership = True # Users can only modify their own posts
_owner_field = "user_id" # Field that stores the owner ID
user_id: str # Automatically set to current user on creation
title: str
content: str
# Now automatically:
# โ
POST /posts/ - Sets user_id to current user
# โ
PUT /posts/{id} - Only owner (or admin) can update
# โ
DELETE /posts/{id} - Only owner (or admin) can delete
# โ
Admins bypass all ownership checks
Three Levels of Protection
1. Public (default) - No authentication required:
class Product(BaseS3Model):
# No security flags - anyone can CRUD
name: str
price: float
2. Auth Required - Must be logged in:
class SiteSettings(BaseS3Model):
_require_auth = True # Any logged-in user can modify
site_name: str
maintenance_mode: bool
3. Ownership Required - Must be owner or admin:
class BlogPost(BaseS3Model):
_require_ownership = True # Only owner can modify
_owner_field = "user_id" # Field containing owner ID
user_id: str # Auto-set on creation
title: str
Admin Users
Users with is_admin=True can bypass all ownership checks.
Default Admin (Development):
S3verless automatically creates a default admin account on startup:
- Username:
admin - Password:
Admin123! - Can be customized via environment variables
# Customize default admin (optional)
export DEFAULT_ADMIN_USERNAME=myadmin
export DEFAULT_ADMIN_PASSWORD=SecurePass123!
export DEFAULT_ADMIN_EMAIL=admin@mysite.com
# Disable in production
export CREATE_DEFAULT_ADMIN=false
Programmatic Admin Creation:
# Create an admin user
admin = await auth_service.create_user(
s3_client, "admin", "admin@site.com", "SecurePass123!"
)
admin.is_admin = True # Make them admin
await user_service.update(s3_client, str(admin.id), admin)
# Admin can now:
# - Modify ANY post (even if user_id doesn't match)
# - Delete ANY comment (even if not theirs)
# - Full access to all ownership-protected resources
See the blog platform example for a complete implementation.
๐ ๏ธ CLI Tool
S3verless includes a CLI for common tasks:
# Create a new project
s3verless init my-app --template ecommerce
# Inspect models
s3verless inspect models.py
# List S3 data
s3verless list-data --bucket my-bucket --prefix products/
# Show version
s3verless version
๐๏ธ Architecture
S3verless uses a simple but powerful architecture:
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ FastAPI โโโโโโถโ S3verless โโโโโโถโ S3 โ
โ Routes โ โ Data Layer โ โ Bucket โ
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ
โโโโโโโโดโโโโโโโ
โ โ
โโโโโโโผโโโโโ โโโโโโผโโโโโโ
โ Query โ โ Auth โ
โ Engine โ โ System โ
โโโโโโโโโโโโ โโโโโโโโโโโโ
๐ Deployment
AWS Lambda
# lambda_function.py
from mangum import Mangum
from main import app
handler = Mangum(app)
Docker
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Local Development
Use LocalStack for S3 emulation:
docker run -d -p 4566:4566 localstack/localstack
๐ Performance Considerations
- Caching: S3verless caches frequently accessed objects
- Indexing: Use
_indexesfor faster queries - Pagination: Always paginate large datasets
- Batch Operations: Use bulk endpoints for multiple operations
๐งช Testing
S3verless includes comprehensive tests:
# Run all tests
pytest
# Run with coverage
pytest --cov=s3verless --cov-report=term-missing
# Run specific test file
pytest tests/test_base.py
๐ Documentation
- Getting Started Guide - Your first S3verless app
- API Reference - Complete API documentation
- Deployment Guide - Deploy to production
- Best Practices - Tips and patterns
- Contributing - How to contribute
๐ฎ Future Work & Roadmap
We're actively working on improving S3verless. Here are some planned features:
Authentication & Security
- Refresh Tokens: Implement refresh token pattern for better security
- Short-lived access tokens (15 min)
- Long-lived refresh tokens (7 days)
- Token rotation on refresh
- Token Versioning: Per-user token version for selective invalidation
- Token Blacklist: Ability to revoke specific tokens
- Secret Rotation: Support multiple valid secrets during rotation period
- OAuth2 Integration: Social login (Google, GitHub, etc.)
- Multi-factor Authentication: 2FA/MFA support
Performance & Scalability
- Caching Layer: Redis/Elasticache integration for hot data
- Connection Pooling: Improved S3 connection management
- Batch Operations: Optimized bulk insert/update/delete
- Smart Indexing: Automatic index suggestions based on query patterns
- Query Optimization: Query plan analysis and optimization
Features
- Full-Text Search: Integration with OpenSearch/Elasticsearch
- File Uploads: Direct S3 upload with presigned URLs
- Real-time Subscriptions: WebSocket support for live updates
- Backup & Restore: Automated backup strategies
- Audit Logging: Track all data changes
- GraphQL Support: Alternative to REST API
- Database Migration: Import from/export to traditional databases
Developer Experience
- Interactive CLI: Better model scaffolding and management
- Type Stubs: Complete type hints for better IDE support
- Visual Admin: Enhanced admin interface with charts
- Testing Utilities: Mock S3 helpers and test fixtures
- Performance Profiling: Built-in query performance monitoring
Want to contribute to any of these? Check out our Contributing Guide!
๐ค Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
# Clone the repository
git clone https://github.com/alexjacobs08/s3verless.git
cd s3verless
# Install uv (if needed)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Install dependencies
uv sync --all-extras
# Run tests
uv run pytest
# Format and lint
uv run ruff format .
uv run ruff check .
๐ License
S3verless is MIT licensed. See LICENSE for details.
๐ Acknowledgments
Inspired by the serverless movement and the desire to simplify backend development.
๐ฆ Publishing to PyPI
See PUBLISH.md for instructions on publishing the package to PyPI.
๐ Links
- PyPI: https://pypi.org/project/s3verless/
- GitHub: https://github.com/alexjacobs08/s3verless
- Issues: https://github.com/alexjacobs08/s3verless/issues
- Changelog: CHANGELOG.md
๐ฌ Support
- GitHub Issues: For bugs and feature requests
- GitHub Discussions: For questions and discussions
Built with โค๏ธ by the S3verless community
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file s3verless-0.1.1.tar.gz.
File metadata
- Download URL: s3verless-0.1.1.tar.gz
- Upload date:
- Size: 67.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2e7686ced15574ec311e75410ef478a8d35468b409476815b2a2c339300ca7f8
|
|
| MD5 |
047f526808c183f24fb5749bde14d723
|
|
| BLAKE2b-256 |
57f828969e91eec4f1e2b3bf5ff387d25eb64b8253be1ba5f94b6a030268a1e9
|
File details
Details for the file s3verless-0.1.1-py3-none-any.whl.
File metadata
- Download URL: s3verless-0.1.1-py3-none-any.whl
- Upload date:
- Size: 45.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6396f377418de845f446b84dc09817afc477f4cf1af7c35ed8143f90ad76d638
|
|
| MD5 |
fabb259e6aa7b4bbc4ea74ab485bcf70
|
|
| BLAKE2b-256 |
f9e51ec7fb0e2860faf5481e8e98150952edb03142b7964e11c09b1d1a014cde
|