fastapi

Detail not found error using FastAPI's APIRouter


I have a directory structure as follows:

app
  >routers
   >items.py
  __init__.py
  main.py

Inside main I have the following code:

from typing import Union
import uvicorn
from fastapi import FastAPI, APIRouter
from routers import items



app = FastAPI()
app.include_router(items.router, prefix='/items', tags=['items'])

@app.get("/")
async def root():
    return {"message": "World World"}

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

Within items.py I have the following:

from fastapi import APIRouter

router = APIRouter(
    prefix="/items",
    tags=["items"]
)

@router.api_route("/items")
async def items():
    return {"test": "items"}

When I run the code, I can go to my url http:127.0.0.0:8000/ and I get the Hello world message. But when i go to http:127.0.0.0:8000/items I'm seeing an error:

{"detail": "not found"}

How do I fix this? I tried debugging this but when I hit my debugger, and type items.router it tells me that I'm correctly importing from the right path.


Solution

  • You prefixed the route with /items three times!

    router = APIRouter(prefix="/items", tags=["items"])
    #                         ^^^^^^^^
    ...
    @router.api_route("/items")
    #                 ^^^^^^^^
    ...
    app.include_router(items.router, prefix='/items', tags=['items'])
    #                                       ^^^^^^^^
    

    This means the endpoint is available at http://127.0.0.1:8000/items/items/items. For that matter you also added the same tag twice, which is unnecessary.

    You also would have seen this by opening up the docs page to view the route specs exported by the openapi.json

    enter image description here

    You only need to specify the route once and tags once per endpoint/routing rule. Try this:

    router = APIRouter(prefix="/items", tags=["items"])
    ...
    @router.api_route("/")
    ...
    app.include_router(items.router)
    

    Full example:

    import uvicorn
    from fastapi import FastAPI, APIRouter
    
    router = APIRouter(prefix="/items", tags=["items"])
    
    
    @router.api_route("/")
    async def items():
        return {"test": "items"}
    
    
    app = FastAPI()
    app.include_router(router)
    
    
    @app.get("/")
    async def root():
        return {"message": "World World"}
    
    
    if __name__ == "__main__":
        uvicorn.run(app, host="0.0.0.0", port=8000)