Home > OS >  FastAPI conflict path parameter in endpoint - good practices?
FastAPI conflict path parameter in endpoint - good practices?

Time:09-30

I am creating 2 GET methods for a resource student using FastAPI. I'm looking to GET a student in 2 ways: by student_id or by student_name.

The issue is that, I initially created the 2 endpoints as follows

@app.get("/student/{student_name}", response_model=schemas.Student, status_code=200)
def get_student_by_name(student_name: str, db: Session = Depends(get_db)):
    db_student = crud.get_student_by_name(db, student_name)
    if db_student is None:
        raise HTTPException(status_code=404, detail="Student not found")
    return db_student


@app.get("/student/{student_id}", response_model=schemas.Student, status_code=200)
def get_student_by_id(student_id: int, db: Session = Depends(get_db)):
    db_student = crud.get_student_by_id(db, student_id)
    if db_student is None:
        raise HTTPException(status_code=404, detail="Student not found")
    return db_student

The problem is that the endpoint names are conflicting with each other, it is both /student followed by a parameter and only one of them could work - in this case only /student/{student_name} because it is defined in the front. So I came up with this simple workaround by adding a bit more to the endpoint names:

@app.get("/student/{student_name}", response_model=schemas.Student, status_code=200)
def get_student_by_name(student_name: str, db: Session = Depends(get_db)):
    db_student = crud.get_student_by_name(db, student_name)
    if db_student is None:
        raise HTTPException(status_code=404, detail="Student not found")
    return db_student


@app.get("/student/byid/{student_id}", response_model=schemas.Student, status_code=200)
def get_student_by_id(student_id: int, db: Session = Depends(get_db)):
    db_student = crud.get_student_by_id(db, student_id)
    if db_student is None:
        raise HTTPException(status_code=404, detail="Student not found")
    return db_student

I added /byid to the endpoint name of the get_student)by_id method. While both endpoints could work now, I am wondering if this is considered a good practice? WHat would be the best practice when one resource needed to be queried with a single path parameter to differentiate the endpoint names?

CodePudding user response:

I will do something like this

@app.get("/student/{student_id}", response_model=schemas.Student, status_code=200)
def get_student(student_id: str, db: Session = Depends(get_db)):
    db_student = crud.get_student_by_id(db, student_id)
    if db_student is None:
        raise HTTPException(status_code=404, detail="Student not found")
    return db_student


# use search criterias as query params
@app.get("/student/", response_model=List[schemas.Student], status_code=200)
def get_students(student_name: string = None, db: Session = Depends(get_db)):
    # Query inside your crud file
    query = db.query(Student)
    if student_name:
        # if you want to search similar items
        query = query.filter(Student.name.like(f"%{student_name}%"))
        # if you want to search an exact match
        query = query.filter(Student.name == student_name)
    
    return query.all()

With this your code will be a little bit more open to future changes, I will only use a url param when searching by id, any other search criteria can be handled as a filter parameter using query params

  • Related