Home > Enterprise >  Endpoint not being executed in FastAPI
Endpoint not being executed in FastAPI

Time:10-04

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.

  • Related