I am developing a simple API using FastAPI.
I have this endpoint which I am testing, that whatever it should return, I always get a 200 code with an empty list. If I try to debug it by printing, returning a 404 or whatever, it keeps returning the same response. It is not the first time it happens using FastAPI.
The rest of endpoints work normally.
I am using Motor to connect to MongoDB, if that may cause any problem.
The problematic endpoint is name_list
The router file:
import editdistance
from datetime import datetime
from motor import motor_asyncio
from fastapi import APIRouter, HTTPException, Body, status
from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse
from app.config import MONGO_URL, DATABASE_NAME
from app.tools import all_to_lower
from app.models.department import Department
from app.logger import logger as log
router = APIRouter()
client = motor_asyncio.AsyncIOMotorClient(MONGO_URL)
db = client[DATABASE_NAME]
@router.post("/insert", response_description="Insert a new department", response_model=Department)
async def insert_department(department: Department = Body(...)):
'''
Inserts or updates a department
'''
department = jsonable_encoder(department)
department = all_to_lower(department)
department['created_at'] = datetime.now()
if department["parent_department"] != "root" and not db.departments.find_one({"name": department["parent_department"]}):
raise HTTPException(status_code=404, detail="Parent department not found")
if not department["owners"]:
raise HTTPException(status_code=400, detail="Owners can't be empty")
for owner in department["owners"]:
if not owner.endswith("@crealsa.es"):
raise HTTPException(status_code=400, detail="Owners must be a valid email ending with @crealsa.es")
parent_exists = await db.departments.find_one({"name": department["parent_department"]})
if department["parent_department"] != "root" and not parent_exists:
raise HTTPException(status_code=404, detail="Parent department not found")
new_department = await db.departments.find_one_and_update(
{"name": department["name"]},
{"$setOnInsert": department},
upsert=True,
return_document=True,
)
created_department = await db.departments.find_one({"_id": new_department["_id"]})
created_department["created_at"] = created_department["created_at"].strftime("%Y-%m-%dT%H:%M:%S")
return JSONResponse(status_code=status.HTTP_201_CREATED, content=created_department)
@router.get("/all", response_description="Get all departments", response_model=list[Department])
async def get_all_departments():
departments = []
async for department in db.departments.find():
departments.append(department)
return departments
@router.get("/{name}", response_description="Get a single department by its name", response_model=list[Department])
async def get_department(name: str):
'''
Get a single department by its name
'''
name = name.lower()
department = await db.departments.find_one({"name": name})
if department:
department["created_at"] = department["created_at"].strftime("%Y-%m-%dT%H:%M:%S")
return [department]
departments = []
async for department in db.departments.find():
departments.append(department)
substr = [dept for dept in departments if name[1:-1] in dept["name"]]
closest = []
for dept in departments:
if editdistance.eval(name, dept["name"]) < 5:
closest.append(dept)
closest = sorted(closest, key=lambda dept: editdistance.eval(name, dept["name"]))
closest = [dept for i, dept in enumerate(closest) if i == 0 or dept["_id"] != closest[i-1]["_id"]]
closest = closest[:10]
result = substr closest
return [dept for i, dept in enumerate(result) if i == 0 or dept["_id"] != result[i-1]["_id"]]
@router.get("/id/{id}", response_description="Get a single department by its id", response_model=Department)
async def get_department_by_id(id: str):
'''
Get a single department by its id
'''
if (department := await db.departments.find_one({"_id": id})) is not None:
return department
raise HTTPException(status_code=404, detail=f"Department {id} not found")
@router.get("/name_list", response_description="Get all departments names", response_model=str)
async def get_all_departments_names():
'''
Returns a list with all departments names
'''
log.info("Getting all departments names")
return HTTPException(status_code=404, detail="No departments found")
CodePudding user response:
Using return
in the last line of method name_list
considers the function to be executed well and return with 200 code. To raise an error, please use raise
key word instead of return
.
Hope you will find it useful.
CodePudding user response:
You have defined a route that catches all requests against /
before the route in question, so you're not executing the endpoint you think you're executing.
@router.get("/{name}", ...)
async def get_department(name: str):
...
This is the endpoint that gets called - with name_list
as the name
.
Instead, define name_list
before you define /{name}
- or better, if you haven't published this to any third party - relocated /{name}
under a prefix, such as /departments/{name}
instead. Generally a resource type qualifier should be present at the beginning of any REST URLs.