Skip to content

Commit e8dee82

Browse files
committed
refactor: change all APIs to more standard endpoints
1 parent ca1312f commit e8dee82

File tree

9 files changed

+84
-83
lines changed

9 files changed

+84
-83
lines changed

easy/controller/base.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ class CrudAPIController(ControllerBase, CrudAPI, metaclass=CrudApiMetaclass):
1111
"""
1212
Base APIController for auto creating CRUD APIs
1313
14-
GET /?pk={id} - Retrieve a single Object
15-
PUT / - Create a single Object
16-
PATCH /?pk={id} - Update fields for an Object
17-
DELETE /?pk={id} - Delete a single Object
18-
GET /get_all - Retrieve multiple Object, paginated
14+
GET /{id} - Retrieve a single Object
15+
PUT /{id} - Create a single Object
16+
PATCH /{id} - Update fields for an Object
17+
DELETE /{id} - Delete a single Object
18+
GET / - Retrieve multiple Object, paginated
1919
GET /filter/?filters={filters_dict}
2020
- Filter Objects with django-orm filter dict, paginated
2121
GET /filter_exclude/?filters={filters_dict}

easy/controller/meta.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,27 +27,27 @@ def __init__(self, service=None): # type: ignore
2727
super().__init__(model=self.model)
2828

2929
# Define Controller APIs for auto generation
30-
async def get_obj(self, request: HttpRequest, pk: int) -> Any:
30+
async def get_obj(self, request: HttpRequest, id: int) -> Any:
3131
"""
32-
GET /?pk={id}
32+
GET /{id}
3333
Retrieve a single Object
3434
"""
35-
return await self.service.get_obj(pk)
35+
return await self.service.get_obj(id)
3636

37-
async def del_obj(self, request: HttpRequest, pk: int) -> Any:
37+
async def del_obj(self, request: HttpRequest, id: int) -> Any:
3838
"""
39-
DELETE /?pk={id}
39+
DELETE /{id}
4040
Delete a single Object
4141
"""
42-
return await self.service.del_obj(pk)
42+
return await self.service.del_obj(id)
4343

4444
@paginate
4545
async def get_objs(
4646
self, request: HttpRequest, maximum: int = None, filters: str = None
4747
) -> Any:
4848
"""
49-
GET /get_all
50-
Retrieve multiple Object
49+
GET /?maximum={int}&filters={filters_dict}
50+
Retrieve multiple Object (optional: maximum # and filters)
5151
"""
5252
if filters:
5353
return await self.service.get_objs(maximum, **json.loads(filters))
@@ -100,20 +100,20 @@ def __new__(mcs, name: str, bases: Tuple[Type[Any], ...], attrs: dict) -> Any:
100100
opts_recursive: Optional[bool] = temp_opts.model_recursive
101101

102102
base_cls_attrs = {
103-
"get_obj": http_get("/", summary="Get")(
103+
"get_obj": http_get("/{id}", summary="Get a single object")(
104104
copy_func(CrudAPI.get_obj) # type: ignore
105105
),
106-
"del_obj": http_delete("/", summary="Delete")(
106+
"del_obj": http_delete("/{id}", summary="Delete a single object")(
107107
copy_func(CrudAPI.del_obj) # type: ignore
108108
),
109-
"get_all": http_get("/get_all", summary="Get All")(
109+
"get_all": http_get("/", summary="Get multiple objects")(
110110
copy_func(CrudAPI.get_objs) # type: ignore
111111
),
112-
"filter_objs": http_get("/filter", summary="Filter")(
112+
"filter_objs": http_get("/filter/", summary="Filter")(
113113
copy_func(CrudAPI.filter_objs) # type: ignore
114114
),
115115
"filter_exclude_objs": http_get(
116-
"/filter_exclude", summary="Filter exclude"
116+
"/filter_exclude/", summary="Filter exclude"
117117
)(
118118
copy_func(CrudAPI.filter_exclude_objs) # type: ignore
119119
),
@@ -143,13 +143,13 @@ async def add_obj( # type: ignore
143143
return await self.service.add_obj(**data.dict())
144144

145145
async def patch_obj( # type: ignore
146-
self, request: HttpRequest, pk: int, data: DataSchema
146+
self, request: HttpRequest, id: int, data: DataSchema
147147
) -> Any:
148148
"""
149-
PATCH /?pk={id}
149+
PATCH /{id}
150150
Update a single field for a Object
151151
"""
152-
return await self.service.patch_obj(pk=pk, payload=data.dict())
152+
return await self.service.patch_obj(id=id, payload=data.dict())
153153

154154
DataSchema.__name__ = (
155155
f"{opts_model.__name__}__AutoSchema({str(uuid.uuid4())[:4]})"
@@ -160,7 +160,7 @@ async def patch_obj( # type: ignore
160160

161161
base_cls_attrs.update(
162162
{
163-
"patch_obj": http_patch("/", summary="Patch/Update")(
163+
"patch_obj": http_patch("/{id}", summary="Patch a single object")(
164164
copy_func(CrudAPI.patch_obj) # type: ignore
165165
),
166166
"add_obj": http_put("/", summary="Create")(

easy/main.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ class EasyAPI(NinjaExtraAPI):
2828
Easy_output: bool = True,
2929
If True, will be encapsulated in BaseAPIResponse
3030
-renderer, default to EasyJSONRenderer
31-
-API docs default to docs_permission_required,only logged in Staff users can visit
3231
-Auto generate AdminAPIs, it will read the following settings:
3332
AUTO_ADMIN_ENABLED_ALL_APPS
3433
AUTO_ADMIN_EXCLUDE_APPS

easy/services/crud.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,17 @@ def __init__(self, model: Type[models.Model]):
1414
super().__init__(model)
1515
self.model = model
1616

17-
async def get_obj(self, pk: int) -> Any:
18-
return await sync_to_async(self._crud_get_obj)(pk)
17+
async def get_obj(self, id: int) -> Any:
18+
return await sync_to_async(self._crud_get_obj)(id)
1919

2020
async def get_objs(self, maximum: int = None, **filters: Any) -> Any:
2121
return await sync_to_async(self._crud_get_objs_all)(maximum, **filters)
2222

23-
async def patch_obj(self, pk: int, payload: Any) -> Any:
24-
return await sync_to_async(self._crud_update_obj)(pk, payload)
23+
async def patch_obj(self, id: int, payload: Any) -> Any:
24+
return await sync_to_async(self._crud_update_obj)(id, payload)
2525

26-
async def del_obj(self, pk: int) -> Any:
27-
return await sync_to_async(self._crud_del_obj)(pk)
26+
async def del_obj(self, id: int) -> Any:
27+
return await sync_to_async(self._crud_del_obj)(id)
2828

2929
async def add_obj(self, **payload: Any) -> Any:
3030
return await sync_to_async(self._crud_add_obj)(**payload)

tests/demo_app/controllers.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
class AutoGenCrudAPIController(CrudAPIController):
2222
"""
2323
For unit testings of the following auto generated APIs:
24-
get/create/patch/delete/get_all/filter/filter_exclude
24+
get/create/patch/delete/filter/filter_exclude
2525
"""
2626

2727
def __init__(self, service: EventService):
@@ -59,16 +59,16 @@ class Meta:
5959
"category",
6060
]
6161

62-
@http_get("/base_response")
62+
@http_get("/base_response/")
6363
async def generate_base_response(self, request):
6464
return BaseApiResponse({"data": "This is a BaseApiResponse."})
6565

66-
@http_get("/qs_paginated", auth=None)
66+
@http_get("/qs_paginated/", auth=None)
6767
@paginate
6868
async def qs_paginated(self, request):
6969
return await self.service.get_event_objs_demo()
7070

71-
@http_get("/qs_list", response=List[EventSchema])
71+
@http_get("/qs_list/", response=List[EventSchema])
7272
async def get_objs_list_with_filter_exclude(self, request):
7373
return await sync_to_async(list)(
7474
await self.service.filter_exclude_objs(
@@ -77,7 +77,7 @@ async def get_objs_list_with_filter_exclude(self, request):
7777
)
7878

7979
@http_get(
80-
"/qs",
80+
"/qs/",
8181
)
8282
async def list_events(self):
8383
qs = await sync_to_async(self.model.objects.all)()
@@ -96,30 +96,30 @@ def __init__(self, service: EventService):
9696
class Meta:
9797
model = Event
9898

99-
@http_get("/must_be_authenticated", permissions=[IsAuthenticated])
99+
@http_get("/must_be_authenticated/", permissions=[IsAuthenticated])
100100
async def must_be_authenticated(self, word: str):
101101
return await self.service.get_identity_demo(word)
102102

103-
@http_get("/must_be_admin_user", permissions=[IsAdminUser])
103+
@http_get("/must_be_admin_user/", permissions=[IsAdminUser])
104104
async def must_be_admin_user(self, word: str):
105105
return await self.service.get_identity_demo(word)
106106

107-
@http_get("/must_be_super_user", permissions=[IsSuperUser])
107+
@http_get("/must_be_super_user/", permissions=[IsSuperUser])
108108
async def must_be_super_user(self, word: str):
109109
return await self.service.get_identity_demo(word)
110110

111-
@http_get("/test_perm_only_super", permissions=[BaseApiPermission])
111+
@http_get("/test_perm_only_super/", permissions=[BaseApiPermission])
112112
async def test_perm_only_super(self, request):
113113
response = await self.service.add_obj(title="test_event_title")
114114
event_id = response.json_data.get("data")["id"]
115115
# return await self.service.get_obj(id=note.id)
116116
return await sync_to_async(self.get_object_or_none)(Event, id=event_id)
117117

118-
@http_get("/test_perm", permissions=[BaseApiPermission])
118+
@http_get("/test_perm/", permissions=[BaseApiPermission])
119119
async def test_perm(self, request, word: str):
120120
return await self.service.get_identity_demo(word)
121121

122-
@http_get("/test_perm_admin_site", permissions=[AdminSitePermission])
122+
@http_get("/test_perm_admin_site/", permissions=[AdminSitePermission])
123123
async def test_perm_admin_site(self, request, word: str):
124124
return await self.service.get_identity_demo(word)
125125

tests/demo_app/test_async_api_permissions.py

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,76 +20,78 @@ async def test_demo(self, easy_api_client):
2020
client = easy_api_client(PermissionAPIController)
2121

2222
response = await client.get(
23-
"/must_be_authenticated?word=authenticated", content_type="application/json"
23+
"/must_be_authenticated/?word=authenticated",
24+
content_type="application/json",
2425
)
26+
print(f"{response.__dict__.items()}")
2527
assert response.status_code == 200
2628
assert response.json().get("data")["says"] == "authenticated"
2729

2830
client = easy_api_client(PermissionAPIController)
2931
response = await client.get(
30-
"/must_be_admin_user?word=admin",
32+
"/must_be_admin_user/?word=admin",
3133
)
3234
assert response.status_code == 403
3335
with pytest.raises(KeyError):
3436
assert response.json().get("data")["says"] == "admin"
3537

3638
client = easy_api_client(PermissionAPIController, is_staff=True)
3739
response = await client.get(
38-
"/must_be_admin_user?word=admin",
40+
"/must_be_admin_user/?word=admin",
3941
)
4042
assert response.status_code == 200
4143
assert response.json().get("data")["says"] == "admin"
4244

4345
client = easy_api_client(PermissionAPIController)
4446
response = await client.get(
45-
"/must_be_super_user?word=superuser",
47+
"/must_be_super_user/?word=superuser",
4648
)
4749
assert response.status_code == 403
4850
with pytest.raises(KeyError):
4951
assert response.json().get("data")["says"] == "superuser"
5052

5153
client = easy_api_client(PermissionAPIController, is_superuser=True)
5254
response = await client.get(
53-
"/must_be_super_user?word=superuser",
55+
"/must_be_super_user/?word=superuser",
5456
)
5557
assert response.status_code == 200
5658
assert response.json().get("data")["says"] == "superuser"
5759

5860
async def test_perm(self, transactional_db, easy_api_client):
5961
client = easy_api_client(PermissionAPIController)
60-
response = await client.get("/test_perm", query=dict(word="normal"))
62+
response = await client.get("/test_perm/", query=dict(word="normal"))
6163
assert response.status_code == 200
6264
assert response.json().get("data")["says"] == "normal"
6365
client = easy_api_client(PermissionAPIController, is_staff=True)
64-
response = await client.get("/test_perm", query=dict(word="staff"))
66+
response = await client.get("/test_perm/", query=dict(word="staff"))
6567
assert response.status_code == 200
6668
assert response.json().get("data")["says"] == "staff"
6769

6870
async def test_perm_only_super(self, transactional_db, easy_api_client):
6971
client = easy_api_client(PermissionAPIController)
70-
response = await client.get("/test_perm_only_super")
72+
response = await client.get("/test_perm_only_super/")
7173
assert response.status_code == 403
7274
assert response.json().get("data") == {
7375
"detail": "You do not have permission to perform this action."
7476
}
7577

7678
client = easy_api_client(PermissionAPIController)
77-
response = await client.get("/test_perm_only_super")
79+
response = await client.get("/test_perm_only_super/")
7880
assert response.status_code == 403
7981
assert response.json().get("data") == {
8082
"detail": "You do not have permission to perform this action."
8183
}
8284

8385
client = easy_api_client(PermissionAPIController, is_superuser=True)
84-
response = await client.get("/test_perm_only_super")
86+
response = await client.get("/test_perm_only_super/")
8587
assert response.status_code == 200
8688
assert response.json().get("data")["title"] == "test_event_title"
8789

8890
async def test_perm_admin_site(self, transactional_db, easy_api_client):
8991
# None-admin users
9092
client = easy_api_client(PermissionAPIController)
9193
response = await client.get(
92-
"/test_perm_admin_site", query=dict(word="non-admin")
94+
"/test_perm_admin_site/", query=dict(word="non-admin")
9395
)
9496
assert response.status_code == 403
9597
assert response.json().get("data") == {
@@ -98,7 +100,7 @@ async def test_perm_admin_site(self, transactional_db, easy_api_client):
98100

99101
# Staff users
100102
client = easy_api_client(PermissionAPIController, is_staff=True)
101-
response = await client.get("/test_perm_admin_site", query=dict(word="staff"))
103+
response = await client.get("/test_perm_admin_site/", query=dict(word="staff"))
102104
assert response.status_code == 200
103105
assert response.json()["data"]["says"] == "staff"
104106

@@ -109,12 +111,12 @@ async def test_perm_auto_apis_delete(self, transactional_db, easy_api_client):
109111
object_data.update(title=f"{object_data['title']}_get")
110112
event = await sync_to_async(Event.objects.create)(**object_data)
111113
response = await client.get(
112-
f"/?pk={event.id}",
114+
f"/{event.id}",
113115
)
114116
assert response.status_code == 403
115117

116118
response = await client.delete(
117-
f"/?pk={event.id}",
119+
f"/{event.id}",
118120
)
119121
assert response.status_code == 403
120122
assert response.json().get("data") == {
@@ -124,11 +126,11 @@ async def test_perm_auto_apis_delete(self, transactional_db, easy_api_client):
124126
# Super users
125127
client = easy_api_client(AutoGenCrudAPIController, is_superuser=True)
126128
await client.delete(
127-
f"/?pk={event.id}",
129+
f"/{event.id}",
128130
)
129131

130132
response = await client.get(
131-
f"/?pk={event.id}",
133+
f"/{event.id}",
132134
)
133135
assert response.status_code == 200
134136
assert response.json().get("code") == 404
@@ -140,7 +142,7 @@ async def test_perm_auto_apis_patch(self, transactional_db, easy_api_client):
140142
event = await sync_to_async(Event.objects.create)(**object_data)
141143

142144
response = await client.get(
143-
f"/?pk={event.id}",
145+
f"/{event.id}",
144146
)
145147
assert response.status_code == 403
146148
assert response.json().get("data") == {
@@ -150,7 +152,7 @@ async def test_perm_auto_apis_patch(self, transactional_db, easy_api_client):
150152
# Staff users
151153
client = easy_api_client(AutoGenCrudAPIController, is_staff=True)
152154
response = await client.get(
153-
f"/?pk={event.id}",
155+
f"/{event.id}",
154156
)
155157
assert response.json().get("data")["title"] == f"{object_data['title']}"
156158

@@ -172,7 +174,7 @@ async def test_perm_auto_apis_patch(self, transactional_db, easy_api_client):
172174

173175
client = easy_api_client(AdminSitePermissionAPIController)
174176
response = await client.patch(
175-
f"/?pk={event.id}", json=new_data, content_type="application/json"
177+
f"/{event.id}", json=new_data, content_type="application/json"
176178
)
177179

178180
assert response.status_code == 403
@@ -183,12 +185,12 @@ async def test_perm_auto_apis_patch(self, transactional_db, easy_api_client):
183185
# Super users
184186
client = easy_api_client(AutoGenCrudAPIController, is_superuser=True)
185187
response = await client.patch(
186-
f"/?pk={event.id}", json=new_data, content_type="application/json"
188+
f"/{event.id}", json=new_data, content_type="application/json"
187189
)
188190
assert response.json().get("data")["pk"] == event.id
189191

190192
response = await client.get(
191-
f"/?pk={event.id}",
193+
f"/{event.id}",
192194
)
193195
assert response.status_code == 200
194196
assert response.json().get("data")["title"] == "AsyncAPIEvent_patch"

0 commit comments

Comments
 (0)