-
-
Notifications
You must be signed in to change notification settings - Fork 162
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add names to routes #106
base: master
Are you sure you want to change the base?
Add names to routes #106
Conversation
This pull request is being automatically deployed with Vercel (learn more). 🔍 Inspect: https://vercel.com/flortz/fastapi-crudrouter/CNzfmvhSrsUUGtrvaiGt8KHKghQq |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @gaganpreet, thanks for this! Its a small yet important fix that will improve integration with openapi. 🚀
As for pluralization, I think it would be tricky to get it 100% grammatically correct. I'm sure you know it is not as simple as just adding an 's' to the end of any string. I am hesitant to bring in another package to handle pluralization more completely. However a crude implementation that covers most cases should be possible. Thoughts?
@@ -60,6 +61,7 @@ def __init__( | |||
response_model=Optional[List[self.schema]], # type: ignore | |||
summary="Get All", | |||
dependencies=get_all_route, | |||
name=f"get_all_{item_name}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
name=f"get_all_{item_name}", | |
name=f"get_all_{prefix}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need item_name
because prefix
is a path prefix for the API and includes slashes. Which made me realise that using prefix for item might also end up with slashes, so I'll change item name to the lowercased schema class name.
@@ -80,6 +83,7 @@ def __init__( | |||
response_model=Optional[List[self.schema]], # type: ignore | |||
summary="Delete All", | |||
dependencies=delete_all_route, | |||
name=f"delete_all_{item_name}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
name=f"delete_all_{item_name}", | |
name=f"delete_all_{prefix}", |
@@ -102,6 +107,7 @@ def __init__( | |||
summary="Update One", | |||
dependencies=update_route, | |||
error_responses=[NOT_FOUND], | |||
name=f"update_one_{item_name}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
name=f"update_one_{item_name}", | |
name=f"update_one_{prefix}", |
@@ -91,6 +95,7 @@ def __init__( | |||
summary="Get One", | |||
dependencies=get_one_route, | |||
error_responses=[NOT_FOUND], | |||
name=f"get_one_{item_name}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
name=f"get_one_{item_name}", | |
name=f"get_one_{prefix}", |
@@ -113,6 +119,7 @@ def __init__( | |||
summary="Delete One", | |||
dependencies=delete_one_route, | |||
error_responses=[NOT_FOUND], | |||
name=f"delete_one_{item_name}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
name=f"delete_one_{item_name}", | |
name=f"delete_one_{prefix}", |
fastapi_crudrouter/core/_base.py
Outdated
@@ -47,6 +47,7 @@ def __init__( | |||
) | |||
|
|||
prefix = str(prefix if prefix else self.schema.__name__).lower() | |||
item_name = prefix |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
item_name = prefix |
@gaganpreet @grigorov to further this, do you have any objections to directly setting the operation id? some sample operation_id / names could be:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
However a crude implementation that covers most cases should be possible. Thoughts?
A possible solution could be what Django does, it uses the class name and simply appends "s" to the name by default, and lets you specify verbose_name
and verbose_name_plural
as part of model options to customise this behaviour.
do you have any objections to directly setting the operation id?
We shouldn't set operation ids by default: they need to be unique across the whole application and if we set operation ids for users by default we'd need an option to disable the feature in case it results in conflicts in their app.
@@ -60,6 +61,7 @@ def __init__( | |||
response_model=Optional[List[self.schema]], # type: ignore | |||
summary="Get All", | |||
dependencies=get_all_route, | |||
name=f"get_all_{item_name}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need item_name
because prefix
is a path prefix for the API and includes slashes. Which made me realise that using prefix for item might also end up with slashes, so I'll change item name to the lowercased schema class name.
Hi @gaganpreet. I ran the master vs this PR and compared the generated openapi spec. You can see this from the Before we merge this PR. I think it would be best if alter the operation_id and title to make them more readble.
Thoughts? Full diff: diff master.json unique-route-names.json
14c14
< "operationId": "get_all_potato_potato_get",
---
> "operationId": "route_potato_get",
43c43
< "title": "Response Get All Potato Potato Get",
---
> "title": "Response Route Potato Get",
69c69
< "operationId": "create_one_potato_potato_post",
---
> "operationId": "route_potato_post",
108c108
< "operationId": "delete_all_potato_potato_delete",
---
> "operationId": "route_potato_delete",
115c115
< "title": "Response Delete All Potato Potato Delete",
---
> "title": "Response Route Potato Delete",
133c133
< "operationId": "get_one_potato_potato__item_id__get",
---
> "operationId": "route_potato__item_id__get",
176c176
< "operationId": "update_one_potato_potato__item_id__put",
---
> "operationId": "route_potato__item_id__put",
229c229
< "operationId": "delete_one_potato_potato__item_id__delete",
---
> "operationId": "route_potato__item_id__delete",
275c275
< "operationId": "get_all_carrot_carrot_get",
---
> "operationId": "route_carrot_get",
303c303
< "title": "Response Get All Carrot Carrot Get",
---
> "title": "Response Route Carrot Get",
330c330
< "operationId": "create_one_carrot_carrot_post",
---
> "operationId": "route_carrot_post",
370c370
< "operationId": "delete_all_carrot_carrot_delete",
---
> "operationId": "route_carrot_delete",
377c377
< "title": "Response Delete All Carrot Carrot Delete",
---
> "title": "Response Route Carrot Delete",
396c396
< "operationId": "get_one_carrot_carrot__item_id__get",
---
> "operationId": "route_carrot__item_id__get",
440c440
< "operationId": "update_one_carrot_carrot__item_id__put",
---
> "operationId": "route_carrot__item_id__put",
494c494
< "operationId": "delete_one_carrot_carrot__item_id__delete",
---
> "operationId": "route_carrot__item_id__delete", |
Hey Adam, busy schedule got in the way. I just looked into the two points you mentioned. First of all, title: it's generated in this part of FastAPI. It looks like a generated field and I don't see a way to override that with something more pleasant. With regards to operation id, it's going through a similar transformation. We can change it to the same value as name (so operation id will look like Default FastAPI operation ids aren't usually pretty which is why I use the simplify operation ids transformation (which prompted this PR in the first place). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm very need this for my new project
Very helpful project, thanks!
I came across a small issue: I use this recipe to simplify the operation ids generated in the OpenAPI schema. A caveat of applying this simplification is that route names have to be unique.
Unfortunately, if no explicit route name is specified, the fallback is
endpoint.__name__
(endpoint here being the endpoint function), which results from this starlette function. In CRUDRouter's case, everything ends up being the same boring value calledroute
.This PR uses the route prefix to assign a unique name to every route. Grammatically, it's not always correct. eg: If your SQLAlchemy table is named users,
get_one_user
is correct, butget_all_user
isn't. I'm not sure if there's already a way to handle pluralisation in the project, maybe that warrants a discussion first?