How to define multiple API endpoints in FastAPI with different paths but the same path parameter?

Question:

I’m working on a project which uses FastAPI. My router file looks like the following:

# GET API Endpoint 1
@router.get("/project/{project_id}/{employee_id}")
async def method_one(
    project_id: str, organization_id: str, session: AsyncSession = Depends(get_db)
):

    try:
        return await CustomController.method_one(
            session, project_id, employee_id
        )
    except Exception as e:
        return custom_exception_handler(e)

# GET API Endpoint 2
@router.get("/project/details/{project_id}")
async def method_two(
    project_id: str, session: AsyncSession = Depends(get_db)
):

    try:
        return await CustomController.method_two(
            session=session, project_id=project_id
        )
    except Exception as e:
        return custom_exception_handler(e)

# GET API Endpoint 3
@router.get("/project/metadata/{project_id}")
async def method_three(
    project_id: str, session: AsyncSession = Depends(get_db)
):
    try:
        return await CustomController.method_three(
            session=session, project_id=project_id
        )
    except Exception as e:
        return custom_exception_handler(e)
        

The obvious expectation of workflow here is: when each of these API endpoints are triggered with their required path parameters, the controller method is executed, as defined in their body.

However, for some strange reason, when API endpoints 2 and 3 are triggered, they are executing the controller method in endpoint 1, i.e., CustomController.method_one().

Upon adding some print() statements in the method method_one() of the router, I’ve observed that method_one() is being called when API endpoint 2 is called, while it is actually supposed to call method_two() in the router. Same is the case with API endpoint 3.

I’m unable to understand why the method body of method_one() is getting executed, when API endpoints 2 and 3 are triggered. Am I missing out something on configuration, or something – can someone please correct me? Thanks!

Asked By: Pranav N

||

Answers:

In FastAPI, as described in this answer, because endpoints are evaluated in order (see FastAPI’s about how order matters), it makes sure that the endpoint you defined first in your app—in this case, that is, /project/{project_id}/...—will be evaluated first. Hence, every time you call one of the other two endpoints, i.e., /project/details/... and /project/metadata/..., the first endpoint is triggered, using details or metadata as the project_id parameter.

Solution

Thus, you need to make sure that the other two endpoints are declared before the one for /project/{project_id}/.... For example:

# GET API Endpoint 1
@router.get("/project/details/{project_id}")
    # ...

# GET API Endpoint 2
@router.get("/project/metadata/{project_id}")
    # ...

# GET API Endpoint 3
@router.get("/project/{project_id}/{employee_id}")
    # ...
Answered By: Chris