Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/request id injection #14

Merged
merged 2 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@
from routes.users import user
from fastapi_pagination import add_pagination
from middlewares.rate_limiter_middleware import RateLimitMiddleware
from middlewares.request_id_injection import RequestIdInjection
from pybreaker import CircuitBreakerError
from dependencies import circuit_breaker
from utils.slack_notification_utils import send_slack_message
import traceback
from middlewares.request_id_injection import request_id_contextvar

# Initializing the swagger docs
app = FastAPI(
Expand All @@ -35,13 +37,14 @@
allow_headers=["*"],
)
app.add_middleware(RateLimitMiddleware)
app.add_middleware(RequestIdInjection)
app.include_router(user, prefix="/user")


# Default API route
@app.get("/")
async def read_main():
1/0
print('Request ID:', request_id_contextvar.get())
return {"response": "service up and running..!"}


Expand Down Expand Up @@ -88,8 +91,12 @@ async def http_exception_handler(request: Request, exc: HTTPException):
async def http_exception_handler(request: Request, exc: Exception):
error_message = f'Error: {str(exc)}'
# Include the traceback in the response for debugging purposes
traceback_str = traceback.format_exc()
send_slack_message({ "text": f'```{traceback_str}```', "request_url": str(request.url), "request_method": str(request.method)})
traceback_str = traceback.format_exc(chain=False)
send_slack_message(
{
"text": f'```\nRequestID: {request_id_contextvar.get()}\nRequest URL: {str(request.url)} \nRequest_method: {str(request.method)} \nTraceback: {traceback_str}```'
}
)

return JSONResponse(
status_code=500,
Expand Down
22 changes: 22 additions & 0 deletions middlewares/request_id_injection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from fastapi import FastAPI
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from fastapi.responses import JSONResponse
import contextvars
import uuid

request_id_contextvar = contextvars.ContextVar("request_id", default=None)

class RequestIdInjection(BaseHTTPMiddleware):
def dispatch(self, request: Request, call_next):
request_id = str(uuid.uuid4())
request_id_contextvar.set(request_id)
try:
return call_next(request)

except Exception as ex:
print(ex)
return JSONResponse(content={"success": False}, status_code=500)

finally:
assert request_id_contextvar.get() == request_id
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,5 @@ flake8
black
pre-commit
pybreaker
pytest-asyncio
pytest-asyncio
contextvars
6 changes: 6 additions & 0 deletions routes/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from utils.user_utils import get_current_user
from typing import Annotated
from fastapi.security import HTTPBearer
from middlewares.request_id_injection import request_id_contextvar

user = APIRouter()

Expand All @@ -23,12 +24,14 @@

@user.post("/register", tags=["Users"])
def register(payload: CreateUser, db: Session = Depends(create_local_session)):
print('Request ID:', request_id_contextvar.get())
response = create_user_dao(data=payload, dbSession=db)
return response


@user.post("/signin", tags=["Users"])
def login(payload: Login, db: Session = Depends(create_local_session)):
print('Request ID:', request_id_contextvar.get())
response = signin(data=payload, dbSession=db)
return response

Expand All @@ -40,17 +43,20 @@ async def profile(
db: Session = Depends(create_local_session),
redis=Depends(get_redis),
):
print('Request ID:', request_id_contextvar.get())
# Here, you can use 'redis' to fetch or store data in Redis cache
response = await get_user_dao(user_id, dbSession=db, redis=redis)
return response


@user.get("/", tags=["Users"], response_model=Page[UserOutResponse])
def list_users(db: Session = Depends(create_local_session)):
print('Request ID:', request_id_contextvar.get())
response = list_users_dao(dbSession=db)
return response


@user.get("/{user_id}/secure-route/", tags=["Users"], dependencies=[Depends(get_current_user)])
def secure_route(token: Annotated[str, Depends(httpBearerScheme)], user_id: int):
print('Request ID:', request_id_contextvar.get())
return {"message": "If you see this, you're authenticated"}