An issue is raised when a FastAPI endpoint uses the generic @app.route() or @router.route() decorator with a methods parameter.

Why is this an issue?

FastAPI provides specific decorators for each HTTP method (@app.get(), @app.post(), @app.put(), @app.delete(), etc.) that are more explicit and idiomatic than using the generic @app.route() decorator with a methods parameter.

The generic route() decorator comes from Flask, where it’s the standard way to define endpoints. However, FastAPI was designed with a different approach that emphasizes clarity and explicitness.

Using specific HTTP method decorators offers several advantages:

While both approaches work functionally, using the generic route() decorator in FastAPI code suggests unfamiliarity with the framework’s conventions and can make the codebase harder to read for developers who expect idiomatic FastAPI patterns.

What is the potential impact?

Using the generic route decorator instead of specific HTTP method decorators reduces code readability and makes the codebase less maintainable. Developers need to read decorator parameters to understand what HTTP method an endpoint accepts, rather than seeing it immediately in the decorator name.

This pattern also signals to other developers that the code may not follow FastAPI best practices, potentially leading to inconsistent coding styles across the project.

How to fix it in FastAPI

Replace the generic @app.route() decorator with the specific HTTP method decorator that matches the method specified in the methods parameter. FastAPI provides decorators for all standard HTTP methods: @app.get(), @app.post(), @app.put(), @app.delete(), @app.patch(), @app.options(), @app.head(), and @app.trace().

Code examples

Noncompliant code example

@app.route("/users", methods=["GET"])  # Noncompliant
def get_users():
    return {"users": []}

Compliant solution

@app.get("/users")
def get_users():
    return {"users": []}

The same principle applies to POST endpoints. Replace @app.route() with @app.post().

Noncompliant code example

@app.route("/users", methods=["POST"])  # Noncompliant
def create_user(user: User):
    return {"user": user}

Compliant solution

@app.post("/users")
def create_user(user: User):
    return {"user": user}

For PUT, DELETE, and other HTTP methods, use the corresponding specific decorator.

Noncompliant code example

@app.route("/items/{item_id}", methods=["DELETE"])  # Noncompliant
def delete_item(item_id: int):
    return {"deleted": item_id}

Compliant solution

@app.delete("/items/{item_id}")
def delete_item(item_id: int):
    return {"deleted": item_id}

The same pattern applies when using APIRouter instead of the main FastAPI app instance.

Noncompliant code example

router = APIRouter()

@router.route("/items", methods=["GET"])  # Noncompliant
def list_items():
    return {"items": []}

Compliant solution

router = APIRouter()

@router.get("/items")
def list_items():
    return {"items": []}

Resources

Documentation