Home > Software engineering >  Is there a way to do the request header check using a decorator in FastAPI?
Is there a way to do the request header check using a decorator in FastAPI?

Time:09-30

I am currently looking at the examples of checking incoming request headers provided in the FastAPI docs.

I am wondering if there is a way to implement the header check using a decorator over the routes, instead of repeating the checking code in every endpoint functions? Something like:

def check_header_api_key(func, *args, **kwargs):
    @wraps(func)
    def wrapper(request: Request):
        if request.headers["SECRET"] != SECRET_KEY:
            raise HTTPException(status_code=401, detail="Invalid client secret")
        return func(request, *args, **kwargs)
    return wrapper


@app.post("/course", response_model=schemas.Course, status_code=200)
@check_header_api_key
def create_course(course: schemas.CourseCreate, request: Request, db: Session = Depends(get_db)):
    db_course = crud.get_course(db, course=course)
    if db_course:
        raise HTTPException(status_code=400, detail="This course has already been created.")
    return crud.create_course(db=db, course=course)

I am familiar how should I handle the parameters into the decorator, can anyone help?

CodePudding user response:

Instead of referring directly to the app object, you can create an APIRouter object, and add the dependency as a dependency for the whole router:

authenticated = APIRouter(dependencies=[Depends(get_authenticated_user)])

You can then add endpoints to this router:

@authenticated.post('/course', ....)

You can compose these router objects as you wish, either directly under your app - or as subrouters under each other:

app.include_router(authenticated)

# or with several sub routers:

authenticated_router = APIRouter(dependencies=[Depends(get_authenticated_user)])
public_router = APIRouter()

authenticated_router.include_router(courses.authenticated)
authenticated_router.include_router(users.authenticated)
public_router.include_router(users.public)
app.include_router(authenticated_router)
app.include_router(public_router)

This way you can compose and move your routers around as necessary to make them require authentication or not, and you can further expand them into admin/private/etc. routers if necessary.

  • Related