From be199a4b8f26f35f44c49df33bd4df20b0699f52 Mon Sep 17 00:00:00 2001 From: Obi Madu Date: Fri, 14 Mar 2025 08:55:36 +0100 Subject: [PATCH] Initial commit from template --- .gitignore | 35 +++++++++++++++++++++++++++++++++++ core/auth.py | 9 +++++++++ core/database.py | 11 +++++++++++ core/router.py | 18 ++++++++++++++++++ endpoints/health.get.py | 11 +++++++++++ endpoints/login.post.py | 25 +++++++++++++++++++++++++ endpoints/signup.post.py | 33 +++++++++++++++++++++++++++++++++ main.py | 19 +++++++++++++++++++ requirements.txt | 5 +++++ 9 files changed, 166 insertions(+) create mode 100644 .gitignore create mode 100644 core/auth.py create mode 100644 core/database.py create mode 100644 core/router.py create mode 100644 endpoints/health.get.py create mode 100644 endpoints/login.post.py create mode 100644 endpoints/signup.post.py create mode 100644 main.py create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8765460 --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class + +# Environment +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Logs +*.log + +# Local development +.settings/ +.vscode/ + +# Database +*.db +*.sqlite + +# Temporary files +*.tmp +*.temp + +# Security +secrets.json +credentials.json + +# IDE specific +.idea/ diff --git a/core/auth.py b/core/auth.py new file mode 100644 index 0000000..7f3d3cf --- /dev/null +++ b/core/auth.py @@ -0,0 +1,9 @@ +from fastapi import Depends, HTTPException +from core.database import fake_users_db + +async def get_current_user_dummy(username: str = "demo"): + """Demo auth dependency""" + user = fake_users_db.get(username) + if not user: + raise HTTPException(status_code=404, detail="User not found") + return user diff --git a/core/database.py b/core/database.py new file mode 100644 index 0000000..43c2986 --- /dev/null +++ b/core/database.py @@ -0,0 +1,11 @@ +from typing import Dict, Any + +# Demo database +fake_users_db: Dict[str, Dict[str, Any]] = { + "demo": { + "id": "7b0a5c28-32aa-4e39-975f-88c8a029a5e2", + "email": "demo@example.com", + "password": "password", + "disabled": False + } +} diff --git a/core/router.py b/core/router.py new file mode 100644 index 0000000..40ae97d --- /dev/null +++ b/core/router.py @@ -0,0 +1,18 @@ +import importlib.util +from pathlib import Path +from fastapi import APIRouter + +def load_endpoints(base_path: Path = Path("endpoints")) -> APIRouter: + router = APIRouter() + + for file_path in base_path.glob("**/*.*.py"): + # Load the module + spec = importlib.util.spec_from_file_location("", file_path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + + # Find the router in the module and include it directly + if hasattr(module, "router"): + router.include_router(module.router) + + return router diff --git a/endpoints/health.get.py b/endpoints/health.get.py new file mode 100644 index 0000000..1f50c77 --- /dev/null +++ b/endpoints/health.get.py @@ -0,0 +1,11 @@ +from fastapi import APIRouter + +router = APIRouter() + +@router.get("/health") +async def health_check(): + """Health check endpoint""" + return { + "status": "ok", + "message": "Service is healthy" + } diff --git a/endpoints/login.post.py b/endpoints/login.post.py new file mode 100644 index 0000000..df5aa08 --- /dev/null +++ b/endpoints/login.post.py @@ -0,0 +1,25 @@ +from fastapi import APIRouter, Depends, HTTPException +from core.auth import get_current_user_dummy +from core.database import fake_users_db + +router = APIRouter() + +@router.post("/login") +async def login_demo( + username: str = "demo", + password: str = "password" +): + """Demo login endpoint""" + user = fake_users_db.get(username) + if not user or user["password"] != password: + raise HTTPException(status_code=400, detail="Invalid credentials") + + return { + "message": "Login successful (demo)", + "user": username, + "token": "dummy_jwt_token_123", + "features": { + "rate_limit": 100, + "expires_in": 3600 + } + } diff --git a/endpoints/signup.post.py b/endpoints/signup.post.py new file mode 100644 index 0000000..47f7fae --- /dev/null +++ b/endpoints/signup.post.py @@ -0,0 +1,33 @@ +from fastapi import APIRouter, HTTPException +from core.database import fake_users_db +import uuid + +router = APIRouter() + +@router.post("/signup") +async def signup_demo( + username: str = "new_user", + email: str = "user@example.com", + password: str = "securepassword123" +): + """Demo signup endpoint""" + if username in fake_users_db: + raise HTTPException(status_code=400, detail="Username already exists") + + user_id = str(uuid.uuid4()) + fake_users_db[username] = { + "id": user_id, + "email": email, + "password": password, + "disabled": False + } + + return { + "message": "User created successfully", + "user_id": user_id, + "username": username, + "next_steps": [ + "Verify your email (demo)", + "Complete profile setup" + ] + } diff --git a/main.py b/main.py new file mode 100644 index 0000000..297cc87 --- /dev/null +++ b/main.py @@ -0,0 +1,19 @@ +from fastapi import FastAPI +from pathlib import Path +from core.router import load_endpoints + +app = FastAPI(title="API Starter Template") + +# Load all endpoints +app.include_router(load_endpoints(Path("endpoints"))) + +@app.get("/") +def root(): + return { + "message": "FastAPI App Running", + "endpoints": { + "health": "/health (GET)", + "login": "/login (POST)", + "signup": "/signup (POST)" + } + } diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..cc9fbcd --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +fastapi>=0.68.0 +uvicorn[standard] +python-multipart +python-jose[cryptography] +passlib[bcrypt]