An issue is raised when a FastAPI endpoint uses the generic @app.route() or @router.route() decorator with a
methods parameter.
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.
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.
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().
@app.route("/users", methods=["GET"]) # Noncompliant
def get_users():
return {"users": []}
@app.get("/users")
def get_users():
return {"users": []}
The same principle applies to POST endpoints. Replace @app.route() with @app.post().
@app.route("/users", methods=["POST"]) # Noncompliant
def create_user(user: User):
return {"user": user}
@app.post("/users")
def create_user(user: User):
return {"user": user}
For PUT, DELETE, and other HTTP methods, use the corresponding specific decorator.
@app.route("/items/{item_id}", methods=["DELETE"]) # Noncompliant
def delete_item(item_id: int):
return {"deleted": item_id}
@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.
router = APIRouter()
@router.route("/items", methods=["GET"]) # Noncompliant
def list_items():
return {"items": []}
router = APIRouter()
@router.get("/items")
def list_items():
return {"items": []}