Set up Python project with uv environment management and FastAPI stack. Project structure: - src/gondulf/ - Main application package - tests/ - Test suite directory - pyproject.toml - Project configuration with dependencies - README.md - Project documentation - uv.lock - Dependency lock file Dependencies configured: - FastAPI + Uvicorn for web framework - SQLAlchemy for database ORM - pytest + coverage for testing - ruff, black, mypy, flake8 for code quality - Development environment using uv direct execution model All project standards reviewed and implemented per: - /docs/standards/coding.md - /docs/standards/testing.md - /docs/standards/git.md - /docs/standards/development-environment.md - /docs/standards/versioning.md
4.8 KiB
4.8 KiB
0001. Python Framework Selection for IndieAuth Server
Date: 2025-11-20
Status
Proposed
Context
We need to select a Python web framework for implementing the IndieAuth server. The requirements are:
- Must support OAuth 2.0/IndieAuth protocol implementation
- Must be simple and maintainable (avoiding Django per user requirement)
- Must handle async operations efficiently
- Must have good security features
- Must be production-ready and well-maintained
- Must not add unnecessary complexity
We evaluated several Python web frameworks considering our core value of simplicity.
Decision
Recommended Stack:
Web Framework: FastAPI
FastAPI is the recommended framework for this project.
Rationale:
- Simplicity with Power: Clean, Pythonic API design that doesn't hide complexity
- Type Hints: Native support for Python type hints with automatic validation
- OAuth 2.0 Ready: Built-in OAuth 2.0 support that we can adapt for IndieAuth
- Async First: Native async/await support for better performance
- Automatic Documentation: OpenAPI/Swagger documentation generated automatically
- Modern Python: Requires Python 3.10+ which aligns with our standards
- No Magic: Explicit routing and dependency injection, no hidden behavior
- Production Ready: Used by Microsoft, Netflix, Uber - battle-tested
Data Storage: SQLite with SQLAlchemy Core
Rationale:
- Simplicity: SQLite for single-admin use case is perfect
- SQLAlchemy Core: Direct SQL-like interface without ORM complexity
- No Migrations Needed Initially: Simple schema we can manage directly
- Upgrade Path: Can switch to PostgreSQL later if needed without code changes
Additional Libraries:
- python-jose[cryptography]: For JWT token handling if needed
- python-multipart: For form data handling
- httpx: For HTTP client operations (fetching client metadata)
- pydantic: Data validation (comes with FastAPI)
- python-dotenv: Environment variable management
- uvicorn: ASGI server for running FastAPI
Alternatives Considered
Flask
- Pros: Minimal, mature, extensive ecosystem
- Cons: Requires many extensions, no native async, more boilerplate for our needs
Starlette (FastAPI's base)
- Pros: Even more minimal than FastAPI
- Cons: Would need to build too much ourselves, against our simplicity principle
Tornado
- Pros: Good async support, mature
- Cons: Older patterns, less modern Python features, smaller ecosystem
aiohttp
- Pros: Excellent async support
- Cons: Lower-level, would require more custom code for OAuth flows
Consequences
Positive Consequences
- Rapid Development: FastAPI's automatic validation and documentation saves time
- Type Safety: Type hints catch errors early
- Clear Architecture: Explicit dependency injection makes data flow obvious
- Good Testing: FastAPI has excellent testing support with TestClient
- Performance: Async support handles concurrent requests efficiently
- Maintainability: Clear, explicit code that's easy to understand
Negative Consequences
- Newer Framework: FastAPI is newer than Flask (but very stable)
- Async Complexity: Developers need to understand async/await
- Fewer Examples: Fewer IndieAuth examples in FastAPI than Flask
Mitigation Strategies
- Use sync functions where async isn't needed - FastAPI supports both
- Provide clear documentation and examples
- Start with simple synchronous code, add async where beneficial
Implementation Plan
Basic Application Structure
from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import OAuth2AuthorizationCodeBearer
app = FastAPI(title="IndieAuth Server")
# Authorization endpoint
@app.get("/auth")
async def authorization_endpoint(
response_type: str,
client_id: str,
redirect_uri: str,
state: str,
code_challenge: Optional[str] = None,
code_challenge_method: Optional[str] = None
):
"""Handle IndieAuth authorization requests."""
pass
# Token endpoint
@app.post("/token")
async def token_endpoint(
grant_type: str,
code: str,
client_id: str,
redirect_uri: str,
code_verifier: Optional[str] = None
):
"""Exchange authorization code for access token."""
pass
# Client registration endpoint
@app.post("/client/register")
async def client_registration_endpoint(
client_name: str,
redirect_uris: List[str]
):
"""Allow clients to self-register."""
pass
This structure is clean, explicit, and follows the IndieAuth specification closely.
Recommendation
FastAPI provides the best balance of simplicity, modern features, and production-readiness for our IndieAuth server implementation. It aligns perfectly with our core value of simplicity while providing all necessary features for a compliant implementation.