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.
@@ -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.2
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
- - `/api/v1/account_app/users`
160
- - `/api/v2/account_app/users`
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
- - `/api/v1/users`
175
- - `/api/v2/users`
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
- - `/users`
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
- - `api/v2/users`
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
- ### 1. `API_BASE_PATH` in settings Must Include ‍‍`{version}`:
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
- ### 2. Using `app_name` in the `endpoint` decorator:
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
- ### 3. Views with Version Less Than `API_MIN_VERSION` Are Automatically Ignored:
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
- ### 4. URLs for Versions Between `API_MIN_VERSION` <= `version` <= `API_MAX_VERSION`:
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
- ### `endpoint` Decorator Function Definition
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=YHyIapxlaQ3IgZnkdjjJ7QXaZxsMFjq-2TY12a5pXAA,3888
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=G2G3PR_QAPNyJuaw7H9BMARSOK8C6GJlHRAL3KmTuCY,3587
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.2.dist-info/LICENSE,sha256=iDPJdze6sBlBBSoB-BIyT2iHfHDGUAaZG3nTFd6m2FQ,1070
14
- django_api_versioning-0.1.2.dist-info/METADATA,sha256=RquKyi92c11LqbzxUNtIYCEH4ZINWc8g0vf2d4u0SR8,10679
15
- django_api_versioning-0.1.2.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
16
- django_api_versioning-0.1.2.dist-info/top_level.txt,sha256=F4n1zaE6P--9OytuMrvCD50vn7NvIVWkIl6ie9fsFck,28
17
- django_api_versioning-0.1.2.dist-info/RECORD,,
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}"