Closed Pk13055 closed 4 years ago
I would like to work on this
I have few doubts regarding this.
The last two can be taken care if implementation of front_end is done correctly. If that is the case then last two are not needed
category_id
from ..models.base import CategoryEnum
if category_id not in CategoryEnum: return ResponseBase(success=False, error=["Invalid category"]) else:
category_id
-named db- No it is not OK, you have to enfore that.
```python
from ..models.base import CategoryEnum
if Movie.category_id != CategoryEnum.movies:
return ResponseBase(success=False, data=...)
else:
# add item successfully
No, frontend just implements basic validation. At the end of the day, it is the responsibility of the backend to ensure incorrect data does not end up in the database.
Ok. For the last one we dont have any category_id
field in our request model, so i manually check for all the required corresponding to a particular field which i think is not a good way of doing that or we can add a category_id field in the request body.
The controller for the add_item_route
is as follows:
@router.post("/{category_id}", response_model=ItemInResponse, dependencies=[Depends(verify_token)], tags=["add"])
async def add_item_route(category_id: str, item: Union[Movie, Anime, Show, Music],
db: AsyncIOMotorClient = Depends(get_database)) -> ItemInResponse:
"""Add item to a given category"""
# TODO add item to db
return {"success": True}
The url itself has the parameter {category_id}
so you can just use that, that's why it's not part of the request model.
Also by the method you told it will return a 200 OK status. Which i dont think is nice. So we can follow something like this from the documention to restrict possible paths. I have verified this for one path it works very well, even in the documentation.
Also we can refer this for setting status codes
The controller for the
add_item_route
is as follows:@router.post("/{category_id}", response_model=ItemInResponse, dependencies=[Depends(verify_token)], tags=["add"]) async def add_item_route(category_id: str, item: Union[Movie, Anime, Show, Music], db: AsyncIOMotorClient = Depends(get_database)) -> ItemInResponse: """Add item to a given category""" # TODO add item to db return {"success": True}
The url itself has the parameter
{category_id}
so you can just use that, that's why it's not part of the request model.
Basically i am saying that if I grab category_id
from url i need to manually check for each required component for each category_id . That is if the url is for movies, and request is of the form shows i need to verify from the request body that the object structure is of the type mentioned in the url
As I had mentioned earlier:
from ..models.base import CategoryEnum
if category_id not in CategoryEnum:
return ResponseBase(success=False, data=...)
else:
# here just add a simple if/else
if category_id == CategoryEnum.movies:
item = Movie(data)
# similarly for all else
# finally add to db
_res = await db[category_id]["data"].insert_one(item.dict())
return ItemInResponse(data=item)
PS: Refer to this for details on models and validation
There are some problems in this. First setting data to elipsis (...) is giving this error.
Which i fixed by not passing any value in data. But the MAJOR problem is that the route expects ItemInResponse model which has data required, but we are sending ResponseBase which has no data, therefore giving this error.
I tried sending an empty dict with data but that didn't work too ( i expected this ) as it requires different fields required. Resulting into this.
Now i am stuck as i dont know how to send error back. I read the link you send but coudn't take out something fruitful.
The solution for this i think is that we validate category_id the way i told earlier using Enum class
from ..models.base import CategoryEnum
if category_id not in CategoryEnum:
return ResponseBase(success=False, error=["Invalid category"])
else:
# add item to `category_id`-named db
@gsc2001 is this working for you? The if condition always returns true for me as checking in CategoryEnum
gives me objects of type CategoryEnum.movies
, etc. How did you access the values in them?
@kjain1810 Yeah I realized that just now. The if condition is also not working. I tried fixing it by casting casting_id to CategoryEnum like this
# just cast category_id to CategoryEnum
category_id = CategoryEnum(category_id)
if category_id not in CategoryEnum:
# now normal
But there is a problem in this also as if category_id is not a CategoryEnum it will result into error like this
All these problems can be fixed if use the method as told in documentation, which I told earlier
@gsc2001 doesn't that just hard codes the different categories that we have?That'll have issues if we want to expand our category list in the future. There must be a better way for this.
@kjain1810 are you referring to method in the documentation or in which i told. The method which is in the documentation is very good we can easily add more categories to it without any hassle by adding then in the CategoryEnum class.
And also we would be needing to hardcode all the categories in one place as we need to create different databases and schemas for each category
@gsc2001 I am unable to understand how the method provided in these documentations would provide us an easy way to add more categories in the future. However, I tried a couple of methods and found this to be the easiest one:
for x in CategoryEnum:
if category_id == x.value:
# do what you have to
return ItemsInResponse(success = False, error = ["Invalid category!"])
Check this out https://stackoverflow.com/a/29795561
Basically you can do:
if category_id not in CategoryEnum.__members__:
# raise an error
else:
# do whatever required
Also for future reference, the code I suggest will probably not work as it’s just meant to illustrate the ideas. Always Google first before trying to implement.
@gsc2001 I am unable to understand how the method provided in these documentations would provide us an easy way to add more categories in the future. However, I tried a couple of methods and found this to be the easiest one:
for x in CategoryEnum: if category_id == x.value: # do what you have to return ItemsInResponse(success = False, error = ["Invalid category!"])
This is bad practice since a loop is run each time And you need it to be category agnostic
So i have figured this out we can send error by raising HTTPException and setting status codes. but initially even if i set 404 status code it sent 200. This could be rectified just by adding status_code in JSONResponse in HTTPException handeler. and convert it to something like this.
async def http_error_handler(request: Request, exc: HTTPException) -> JSONResponse:
return JSONResponse({"errors": [exc.detail]}, status_code=exc.status_code)
and raising the HTTPException like this:-
if category_id not in CategoryEnum.__members__:
raise HTTPException(status_code=404, detail="Category ID not found")
And all of this works pretty well.
Bson is not able to encode Set of typing. Its showing error as follows What can be done . I searched on google and found this but this requires a lot of changes. And also why cant we use simple List in place of Set?
Okay best option is convert it to a list and use $addToSet
instead of $push
You mean to use these these while updating ?
Yes, $addToSet
will avoid adding new genres if they already exist in the array
Things to note:
add_item_route
:route-fix
, so eg:get_category_route-fix
Final merge request will be of
Things to note:
add_item_route
:route-fix
, so eg:get_category_route-fix
Final merge request will be of