django-api-versioning 0.1.2__py3-none-any.whl → 0.1.4__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- django_api_versioning/decorators.py +6 -0
- {django_api_versioning-0.1.2.dist-info → django_api_versioning-0.1.4.dist-info}/METADATA +61 -13
- {django_api_versioning-0.1.2.dist-info → django_api_versioning-0.1.4.dist-info}/RECORD +7 -7
- tests/test_decorators.py +34 -0
- {django_api_versioning-0.1.2.dist-info → django_api_versioning-0.1.4.dist-info}/LICENSE +0 -0
- {django_api_versioning-0.1.2.dist-info → django_api_versioning-0.1.4.dist-info}/WHEEL +0 -0
- {django_api_versioning-0.1.2.dist-info → django_api_versioning-0.1.4.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,6 @@
|
|
1
1
|
from functools import wraps
|
2
2
|
from typing import Callable, Optional, List
|
3
|
+
from django.views import View
|
3
4
|
from .settings import api_settings as settings
|
4
5
|
from .registry import registry
|
5
6
|
from .exceptions import InvalidVersionError, VersionRangeError, VersionTypeError
|
@@ -41,8 +42,13 @@ def endpoint(
|
|
41
42
|
"""
|
42
43
|
|
43
44
|
def decorator(func: Callable) -> Callable:
|
45
|
+
|
44
46
|
@wraps(func)
|
45
47
|
def view(*args, **kwargs):
|
48
|
+
# Check if the view is a class-based view (CBV)
|
49
|
+
if isinstance(func, type) and issubclass(func, View):
|
50
|
+
# For class-based views, ensure it's called as a method
|
51
|
+
return func.as_view()(*args, **kwargs)
|
46
52
|
return func(*args, **kwargs)
|
47
53
|
|
48
54
|
# Read API versioning settings
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: django-api-versioning
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.4
|
4
4
|
Summary: Django API versioning decorator provides a solution for managing multiple API versions within the Django framework, enabling versioning through URLs with backward compatibility and automatically registering routes.
|
5
5
|
Home-page: https://github.com/mojtaba-arvin/django-api-versioning
|
6
6
|
Author: Mojtaba Arvin
|
@@ -118,6 +118,11 @@ def users_view(request):
|
|
118
118
|
|
119
119
|
In this example, the `users_view` function is decorated with the endpoint decorator. This specifies that the view is accessible under version `2` of the API and **supports backward compatibility**. The `backward=True` flag as default ensures that users can also access the previous version (version `1`) at `/api/v1/account_app/users`.
|
120
120
|
|
121
|
+
```bash
|
122
|
+
api/v1/account_app/users [name='users_list_api']
|
123
|
+
api/v2/account_app/users [name='users_list_api']
|
124
|
+
```
|
125
|
+
|
121
126
|
#### Example for Class-Based Views (CBVs):
|
122
127
|
|
123
128
|
For class-based views, you can apply the decorator to methods such as `get`, `post`, or any other HTTP method you need to handle. Here’s an example:
|
@@ -142,11 +147,13 @@ If you have already installed [Django Rest Framework](https://www.django-rest-fr
|
|
142
147
|
|
143
148
|
```python
|
144
149
|
from rest_framework.views import APIView
|
150
|
+
from rest_framework.permissions import AllowAny
|
145
151
|
from rest_framework.response import Response
|
146
152
|
from django_api_versioning.decorators import endpoint
|
147
153
|
|
148
154
|
@endpoint("users", version=2, app_name='account_app', view_name="users_list_api")
|
149
155
|
class UsersAPIView(APIView):
|
156
|
+
permission_classes = [AllowAny]
|
150
157
|
|
151
158
|
def get(self, request):
|
152
159
|
return Response({"message": "API Version 2 Users"})
|
@@ -154,10 +161,12 @@ class UsersAPIView(APIView):
|
|
154
161
|
|
155
162
|
#### URL Generation Based on Versioning:
|
156
163
|
|
157
|
-
Once the decorator is applied, the URLs for your API will be generated based on the version specified in the decorator. For example, if the `API_MIN_VERSION` in your settings.py is set to `1` and the version in the decorator is set to `2`, the following URLs will be available:
|
164
|
+
Once the decorator is applied, the URLs for your API will be generated based on the version specified in the decorator. For example, if the `API_MIN_VERSION` in your `settings.py` is set to `1` and the version in the decorator is set to `2`, the following URLs will be available:
|
158
165
|
|
159
|
-
|
160
|
-
|
166
|
+
```bash
|
167
|
+
api/v1/account_app/users [name='users_list_api']
|
168
|
+
api/v2/account_app/users [name='users_list_api']
|
169
|
+
```
|
161
170
|
|
162
171
|
The `API_MIN_VERSION` setting ensures that users can access the API using different versions, providing backward compatibility. You can adjust which versions are considered valid by modifying the `API_MIN_VERSION` and `version` numbers in the decorators.
|
163
172
|
|
@@ -171,8 +180,10 @@ The `API_MIN_VERSION` setting ensures that users can access the API using differ
|
|
171
180
|
|
172
181
|
The generated URLs will be:
|
173
182
|
|
174
|
-
|
175
|
-
|
183
|
+
```bash
|
184
|
+
api/v1/users [name='users_list_api']
|
185
|
+
api/v2/users [name='users_list_api']
|
186
|
+
```
|
176
187
|
|
177
188
|
**Without `version`:** If you don't pass `version` in the decorator, like this:
|
178
189
|
|
@@ -182,7 +193,9 @@ The generated URLs will be:
|
|
182
193
|
|
183
194
|
API versioning will be disabled (`API_BASE_PATH` as prefix will be removed) for that view. The only URL generated will be:
|
184
195
|
|
185
|
-
|
196
|
+
```bash
|
197
|
+
users [name='users_list_api']
|
198
|
+
```
|
186
199
|
|
187
200
|
**Setting `backward=False`:** By default, the `backward` parameter is set to `True`, which ensures backward compatibility. If you explicitly set `backward=False`, like this:
|
188
201
|
|
@@ -192,7 +205,9 @@ API versioning will be disabled (`API_BASE_PATH` as prefix will be removed) for
|
|
192
205
|
|
193
206
|
The generated URL will be only version 2:
|
194
207
|
|
195
|
-
|
208
|
+
```bash
|
209
|
+
api/v2/users [name='users_list_api']
|
210
|
+
```
|
196
211
|
|
197
212
|
4. Run the Server:
|
198
213
|
|
@@ -202,23 +217,56 @@ python manage.py runserver
|
|
202
217
|
|
203
218
|
## Notes
|
204
219
|
|
205
|
-
|
220
|
+
#### 1. `API_BASE_PATH` in settings Must Include `{version}`:
|
206
221
|
|
207
222
|
The `API_BASE_PATH` should always include `{version}` to ensure proper API versioning. This is important for correctly mapping API routes to different versions.
|
208
223
|
|
209
|
-
|
224
|
+
#### 2. Using `app_name` in the `endpoint` decorator:
|
210
225
|
|
211
226
|
It's recommended to fill in the `app_name` in the `endpoint` decorator to make the API URLs **more unique and organized**. This ensures that the routes are scoped under the correct app, avoiding potential conflicts and making them easier to manage.
|
212
227
|
|
213
|
-
|
228
|
+
#### 3. Behavior When Resolving a Route:
|
229
|
+
|
230
|
+
When resolving the route using Django's `reverse()` function or any other method to resolve the URL, the latest version (highest version number) of the API will be returned. In this example, route for version 3 would be resolved:
|
231
|
+
|
232
|
+
```python
|
233
|
+
from django_api_versioning.decorators import endpoint
|
234
|
+
from django.http import JsonResponse
|
235
|
+
from django.views import View
|
236
|
+
from django.urls import reverse
|
237
|
+
|
238
|
+
|
239
|
+
@endpoint("users", version=3, app_name='account_app', view_name="users_list_api")
|
240
|
+
class UsersView(View):
|
241
|
+
|
242
|
+
def get(self, request):
|
243
|
+
|
244
|
+
return JsonResponse({"path of users_list_api view is": reverse('users_list_api')})
|
245
|
+
```
|
246
|
+
|
247
|
+
response body:
|
248
|
+
|
249
|
+
```json
|
250
|
+
{ "path of users_list_api view is": "api/v3/account_app/users" }
|
251
|
+
```
|
252
|
+
|
253
|
+
The generated URLs will be:
|
254
|
+
|
255
|
+
```bash
|
256
|
+
api/v1/account_app/users [name='users_list_api']
|
257
|
+
api/v2/account_app/users [name='users_list_api']
|
258
|
+
api/v3/account_app/users [name='users_list_api']
|
259
|
+
```
|
260
|
+
|
261
|
+
#### 4. Views with Version Less Than `API_MIN_VERSION` Are Automatically Ignored:
|
214
262
|
|
215
263
|
Any view whose `version` is less than the `API_MIN_VERSION` will be automatically ignored. This means clients will no longer have access to these older versions, **without the need to manually edit or remove code**. This is handled automatically by the package.
|
216
264
|
|
217
|
-
|
265
|
+
#### 5. URLs for Versions Between `API_MIN_VERSION` <= `version` <= `API_MAX_VERSION`:
|
218
266
|
|
219
267
|
Endpoints that have versions within the range defined by `API_MIN_VERSION` <= `version` <= `API_MAX_VERSION` will always have a corresponding URL generated. This ensures that only valid versions will be accessible, providing flexibility in version management.
|
220
268
|
|
221
|
-
|
269
|
+
## `endpoint` Decorator Function Definition
|
222
270
|
|
223
271
|
The `endpoint` decorator is designed to register API views with versioning support in a Django application. It provides flexibility in managing versioned endpoints and ensures backward compatibility with previous versions of the API.
|
224
272
|
|
@@ -1,17 +1,17 @@
|
|
1
1
|
django_api_versioning/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
django_api_versioning/decorators.py,sha256=
|
2
|
+
django_api_versioning/decorators.py,sha256=5xWC5gIeDvkaH9UqmLv5eL0FxQ856451_QLMMi_7ex8,4180
|
3
3
|
django_api_versioning/exceptions.py,sha256=MgCpaNBsD8laQoVIVK823_t1liQ82K_uqguuA60PxXQ,485
|
4
4
|
django_api_versioning/registry.py,sha256=FCRTHGyl995U1kLlxtIBp3lb62v-6AbSK9k3orzZxWA,1140
|
5
5
|
django_api_versioning/settings.py,sha256=8p57CIEQR65luxU7xo-eYdH-lSGGk3-BQFMVRRFG2pY,2975
|
6
6
|
django_api_versioning/urls.py,sha256=B8UBYSXdyq_xTpWeN5zzH2SQzKiqZQMx3WFBrsu93X0,144
|
7
7
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
-
tests/test_decorators.py,sha256=
|
8
|
+
tests/test_decorators.py,sha256=qtscdA3Sz7eZBwtjSXKBkfOZBcRk2ckm8i1E5t-ihUs,5104
|
9
9
|
tests/test_exceptions.py,sha256=fsyfA7ouIMqz6Emexqo_oB7oVEZlhqptNmwH8KX37s8,863
|
10
10
|
tests/test_registry.py,sha256=KQT6yWkfKZmcLShFkidHwfJfPi8yHN5i9xuzC3vqDso,2634
|
11
11
|
tests/test_settings.py,sha256=SjieOTnwHdU0E6A2-qLE3iXG5osY3qacbAzJJ7tqD-0,5213
|
12
12
|
tests/test_urls.py,sha256=DA8DbIEAYX812Re2PlTkL1OpkwCO2IZ1vW_QMh2d9nI,1207
|
13
|
-
django_api_versioning-0.1.
|
14
|
-
django_api_versioning-0.1.
|
15
|
-
django_api_versioning-0.1.
|
16
|
-
django_api_versioning-0.1.
|
17
|
-
django_api_versioning-0.1.
|
13
|
+
django_api_versioning-0.1.4.dist-info/LICENSE,sha256=iDPJdze6sBlBBSoB-BIyT2iHfHDGUAaZG3nTFd6m2FQ,1070
|
14
|
+
django_api_versioning-0.1.4.dist-info/METADATA,sha256=uqQZKUCxfsrirTnOXWIEEFCIO2EAtjsI9Z2GjLS_VFc,11994
|
15
|
+
django_api_versioning-0.1.4.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
16
|
+
django_api_versioning-0.1.4.dist-info/top_level.txt,sha256=F4n1zaE6P--9OytuMrvCD50vn7NvIVWkIl6ie9fsFck,28
|
17
|
+
django_api_versioning-0.1.4.dist-info/RECORD,,
|
tests/test_decorators.py
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
import pytest
|
2
2
|
from unittest.mock import patch
|
3
|
+
from django.http import JsonResponse
|
4
|
+
from django.views import View
|
3
5
|
from django_api_versioning.settings import api_settings as settings
|
4
6
|
from django_api_versioning.registry import registry
|
5
7
|
from django_api_versioning.decorators import endpoint
|
6
8
|
from django_api_versioning.exceptions import InvalidVersionError, VersionTypeError, VersionRangeError
|
7
9
|
|
10
|
+
|
8
11
|
@pytest.fixture(autouse=True)
|
9
12
|
def clear_registered_routes():
|
10
13
|
"""Clear the registry before each test to ensure isolation."""
|
@@ -86,3 +89,34 @@ def test_missing_api_version_settings():
|
|
86
89
|
@endpoint("users", version=2)
|
87
90
|
def test_view():
|
88
91
|
pass
|
92
|
+
|
93
|
+
def test_class_based_view(mock_settings):
|
94
|
+
# Create a class-based view and decorate it with the `endpoint` decorator
|
95
|
+
@endpoint("users", version=2)
|
96
|
+
class UsersView(View):
|
97
|
+
def get(self, request):
|
98
|
+
return JsonResponse({"message": "API Version 2 Users"})
|
99
|
+
|
100
|
+
# Register the view and check if the route is correctly registered
|
101
|
+
registered_routes = [str(p.pattern) for p in registry.urlpatterns]
|
102
|
+
assert "api/v2/users" in registered_routes, f"Route for version 2 is missing: {registered_routes}"
|
103
|
+
|
104
|
+
def test_class_based_view_with_invalid_version(mock_settings):
|
105
|
+
# Test invalid version for class-based view
|
106
|
+
with pytest.raises(InvalidVersionError):
|
107
|
+
@endpoint("users", version=4)
|
108
|
+
class UsersView(View):
|
109
|
+
def get(self, request):
|
110
|
+
return JsonResponse({"message": "API Version 4 Users"})
|
111
|
+
|
112
|
+
def test_class_based_view_with_backward_compatibility(mock_settings):
|
113
|
+
# Test class-based view with backward compatibility
|
114
|
+
@endpoint("users", version=3)
|
115
|
+
class UsersView(View):
|
116
|
+
def get(self, request):
|
117
|
+
return JsonResponse({"message": "API Version 3 Users"})
|
118
|
+
|
119
|
+
registered_routes = [str(p.pattern) for p in registry.urlpatterns]
|
120
|
+
# Assert that versions 1, 2, and 3 are registered for backward compatibility
|
121
|
+
for version in range(1, 4):
|
122
|
+
assert f"api/v{version}/users" in registered_routes, f"Missing route for v{version}: {registered_routes}"
|
File without changes
|
File without changes
|
{django_api_versioning-0.1.2.dist-info → django_api_versioning-0.1.4.dist-info}/top_level.txt
RENAMED
File without changes
|