dmontagu / fastapi-utils

Reusable utilities for FastAPI
MIT License
1.84k stars 163 forks source link

[BUG]match to wrong router method if prefix is same #280

Open fishjam opened 10 months ago

fishjam commented 10 months ago

Describe the bug I create a user.py to check fastapi-utils, there are 4 method.

when I try execute the query_by_name, seems it match to /user/{user_id}. and get HTTP/1.1 422 Unprocessable Entity Error.

Screenshots image

Environment:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import http.client

from fastapi import Body, Query
from fastapi_utils.cbv import cbv
from pydantic import BaseModel, Field

from demos.routers.common import router
from fjutils.logHelper import logger
from tools.common.webSupport import CommonResponse, ResponseFactory

class User(BaseModel):
    id: int = Field(..., description="User id")
    name: str = Field(..., description="User name")

@cbv(router)
class UserRouter:
    def __init__(self):
        logger.info("Enter UserRouter.__init__")  # TODO: every router method will print this

    user_maps = {
        1: User(id=1, name="userA"),
        2: User(id=2, name="userB"),
        3: User(id=3, name="userC"),
        4: User(id=4, name="userD"),
        5: User(id=5, name="userE"),
    }

    @router.get("/user", tags=["User"])
    async def get_user_list(self, skip: int = 0, limit: int = 10) -> CommonResponse:
        logger.info(f"get user list, len={len(self.user_maps)}, self={self}")
        return ResponseFactory.ok(list(self.user_maps.values())[skip: skip + limit])

    @router.post("/user", tags=["User"])
    async def create_user(self, user: User = Body(...)) -> CommonResponse:
        self.user_maps[user.id] = user
        logger.info(f"input user={user}, len(user_maps)={len(self.user_maps)}, self={self}")
        return ResponseFactory.ok(user)

    @router.get("/user/{user_id}", tags=["User"])
    async def get_user_by_id(self, user_id: int) -> CommonResponse:
        logger.info(f"get user by id={user_id}")
        if user_id in self.user_maps:
            return ResponseFactory.ok(self.user_maps.get(user_id))
        else:
            return ResponseFactory.error(http.HTTPStatus.NOT_FOUND, "not found", None)

    @router.get("/user/query_by_name", tags=["User"])  # , response_model=CommonResponse[list(User)]
    async def query_user_by_name(self, name: str = Query(..., max_length=10)) -> CommonResponse:
        logger.info(f"query name={name}")
        result = []
        for k, v in self.user_maps.items():
            if name.upper() in v.upper():
                result.append(v)
        return ResponseFactory.ok(result)

Additional context BTW: I add log in __init__ method, I found every I execute the rest api, the __init__ will execute, is it right?

priyanshu-panwar commented 9 months ago
 @router.get("/user/{name}", tags=["User"])  # , response_model=CommonResponse[list(User)]
    async def query_user_by_name(self, name: str = Query(..., max_length=10)) -> CommonResponse:

You should use something like this