Skip to content

Commit 08ce905

Browse files
committed
[SAM-260011]: feat: restructure FastAPI application and implement new routing
1 parent b01c506 commit 08ce905

6 files changed

Lines changed: 169 additions & 221 deletions

File tree

src/sample/__main__.py

Lines changed: 3 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,12 @@
1-
import logging
2-
from contextlib import asynccontextmanager
3-
from pathlib import Path
4-
5-
from fastapi import FastAPI, Request
6-
from fastapi.responses import HTMLResponse
7-
from fastapi.staticfiles import StaticFiles
8-
from fastapi.templating import Jinja2Templates
9-
from sample.db.connection import connect_db
101
from sample.utils.constants import PORT
112

12-
from . import __version__
13-
14-
15-
@asynccontextmanager
16-
async def lifespan(app: FastAPI):
17-
# Startup logic
18-
print("🏷️ Sample version:", __version__)
19-
logging.info("Starting FastAPI server...")
20-
try:
21-
db = connect_db()
22-
print(f"Using database: {db.name}")
23-
except Exception as e:
24-
logging.error(f"⚠️ Database connection failed: {e}")
25-
print("App is ready.")
26-
27-
yield # <-- control passes to request handling
28-
29-
# Shutdown logic
30-
logging.info("Shutting down FastAPI server...")
31-
# If you want to close DB connections, do it here
32-
33-
34-
# Create FastAPI app with lifespan handler
35-
app = FastAPI(lifespan=lifespan)
36-
37-
# Mount assets and pages
38-
app.mount("/static", StaticFiles(directory="assets"), name="static")
39-
40-
# Point Jinja2 to your templates directory
41-
templates = Jinja2Templates(
42-
directory=str(Path(__file__).resolve().parents[2] / "templates")
43-
)
44-
45-
46-
@app.get("/", response_class=HTMLResponse)
47-
async def index(request: Request):
48-
"""Serve the main index.html at root."""
49-
return templates.TemplateResponse("index.html", {"request": request})
50-
51-
52-
@app.get("/faq", response_class=HTMLResponse)
53-
async def faq(request: Request):
54-
return templates.TemplateResponse("faq.html", {"request": request})
55-
56-
57-
templates = Jinja2Templates(directory="templates")
58-
59-
60-
@app.get("/{full_path:path}", response_class=HTMLResponse)
61-
async def catch_all(request: Request, full_path: str):
62-
return templates.TemplateResponse("404.html", {"request": request}, status_code=404)
63-
643

654
def main():
665
"""Entry point for CLI dev command."""
67-
import uvicorn
6+
from sample.api.main import start
687

69-
uvicorn.run("sample.__main__:app", host="127.0.0.1", port=PORT, reload=True)
8+
print(f"🚀 Starting Sample app on port {PORT}...\n")
9+
start()
7010

7111

7212
if __name__ == "__main__":

src/sample/api/fast_api.py

Lines changed: 0 additions & 157 deletions
This file was deleted.

src/sample/api/main.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import logging
2+
from contextlib import asynccontextmanager
3+
from pathlib import Path
4+
5+
from fastapi import FastAPI
6+
from fastapi.staticfiles import StaticFiles
7+
from fastapi.templating import Jinja2Templates
8+
from sample import __version__
9+
from sample.api.routes import api_router
10+
from sample.api.web_page import web_router
11+
from sample.db.connection import connect_db
12+
from sample.utils.constants import PORT
13+
14+
15+
@asynccontextmanager
16+
async def lifespan(app: FastAPI):
17+
print("🏷️ Sample version:", __version__)
18+
logging.info("Starting FastAPI server...")
19+
try:
20+
db = connect_db()
21+
print(f"Using database: {db.name}")
22+
except Exception as e:
23+
logging.error(f"⚠️ Database connection failed: {e}")
24+
25+
yield
26+
27+
logging.info("Shutting down FastAPI server...")
28+
29+
30+
app = FastAPI(
31+
title="Sample API",
32+
version=__version__,
33+
lifespan=lifespan,
34+
)
35+
36+
# Static
37+
app.mount("/static", StaticFiles(directory="assets"), name="static")
38+
39+
# Templates
40+
templates = Jinja2Templates(
41+
directory=str(Path(__file__).resolve().parent / "templates")
42+
)
43+
44+
45+
app.include_router(web_router)
46+
app.include_router(api_router)
47+
48+
49+
def start():
50+
import uvicorn
51+
52+
uvicorn.run("sample.api.main:app", host="127.0.0.1", port=PORT, reload=True)

src/sample/api/routes.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
from fastapi import APIRouter, HTTPException, Request
2+
from pydantic import BaseModel
3+
from sample.utils.constants import API_PREFIX, GREETING
4+
from sample.utils.helper import normalize_name
5+
from starlette.responses import HTMLResponse, JSONResponse
6+
7+
api_router = APIRouter(prefix=API_PREFIX, tags=["V1"])
8+
9+
10+
class GreetRequest(BaseModel):
11+
name: str
12+
13+
14+
class GreetResponse(BaseModel):
15+
message: str
16+
17+
18+
@api_router.get("/health")
19+
def health_check():
20+
return {"status": "ok"}
21+
22+
23+
@api_router.post("/greet", response_model=GreetResponse)
24+
def greet_user(payload: GreetRequest):
25+
clean_name = normalize_name(payload.name)
26+
27+
if not clean_name:
28+
raise HTTPException(status_code=400, detail="Invalid name provided")
29+
30+
return {"message": f"{GREETING}, {clean_name} 👋"}
31+
32+
33+
@api_router.get("/version", tags=["Version"])
34+
def version():
35+
return {"version": api_router.version}
36+
37+
38+
@api_router.get("/index", response_class=HTMLResponse, tags=["Home"])
39+
async def read_root(request: Request):
40+
return """
41+
<html>
42+
<head>
43+
<title>🎉 Sample Api 🎉</title>
44+
<style>
45+
body {
46+
background: linear-gradient(to right, #268387, #e3898a);
47+
text-align: center;
48+
padding-top: 10%;
49+
color: #fff;
50+
}
51+
h1 {
52+
font-size: 3em;
53+
margin-bottom: 0.2em;
54+
}
55+
p {
56+
font-size: 1.2em;
57+
}
58+
a {
59+
color: #fff;
60+
background: #4CAF50;
61+
padding: 10px 20px;
62+
text-decoration: none;
63+
border-radius: 10px;
64+
font-weight: bold;
65+
transition: background 0.3s ease;
66+
}
67+
a:hover {
68+
background: #45a049;
69+
}
70+
</style>
71+
</head>
72+
<body>
73+
<h1>🎈 This is sample API Tool 🎈</h1>
74+
<p>Explore the <a href="/docs">API Documentation</a></p>
75+
</body>
76+
</html>
77+
"""
78+
79+
80+
@api_router.get("/help", tags=["Help"])
81+
def get_help():
82+
return JSONResponse(
83+
status_code=200,
84+
content={
85+
"message": "Welcome to the Sample BoilerPlate API! Visit /docs for API documentation."
86+
},
87+
)

0 commit comments

Comments
 (0)