Skip to content

Commit eb4d87f

Browse files
authored
move fix for no_content responses to resource layer (#179)
* move fix for no_content responses to resource layer * bump the version * update changelog
1 parent a87d604 commit eb4d87f

File tree

8 files changed

+32
-18
lines changed

8 files changed

+32
-18
lines changed

.bumpversion.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 0.34.0
2+
current_version = 0.34.1
33

44
[bumpversion:file:pyproject.toml]
55

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
# [Unreleased]
88

9+
# [0.34.1]
10+
- [PR 179](https://github.com/salesforce/django-declarative-apis/pull/179) Move the 204 response handling fix to resources.
11+
912
# [0.34.0]
1013
- [PR 178](https://github.com/salesforce/django-declarative-apis/pull/178) Fix JSONEmitter for empty response bodies.
1114

django_declarative_apis/resources/emitters.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -183,19 +183,14 @@ def decode(self, data):
183183
def render(self, request):
184184
cb = request.GET.get("callback", None)
185185
assert cb is None, "JSONP Callbacks not supported"
186-
seria = self.decode(self.construct())
187-
if isinstance(seria, list):
188-
if len(seria) == 0 or (len(seria) == 1 and len(seria[0]) == 0):
189-
# the body is empty, no need to run json.dumps
190-
return ""
191186

192187
# Callback
193188
# TODO: do we care about JSONP?
194189
# if cb and is_valid_jsonp_callback_value(cb):
195190
# return '%s(%s)' % (cb, seria)
196191

197192
return json.dumps(
198-
seria,
193+
self.decode(self.construct()),
199194
cls=DjangoJSONEncoder,
200195
ensure_ascii=False,
201196
indent=4,

django_declarative_apis/resources/resource.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,10 @@ def __call__(self, request, *args, **kwargs): # noqa: C901
301301
srl = emitter(result, handler, anonymous)
302302

303303
try:
304+
# If the status code is 204, we need to return an empty response. skip the emitter.
305+
if status_code == http.HTTPStatus.NO_CONTENT:
306+
return HttpResponse(b"", status=http.HTTPStatus.NO_CONTENT)
307+
304308
"""
305309
Decide whether or not we want a generator here,
306310
or we just want to buffer up the entire result

docs/source/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
# built documents.
7676

7777
# The full version, including alpha/beta/rc tags.
78-
release = "0.34.0" # set by bumpversion
78+
release = "0.34.1" # set by bumpversion
7979

8080
# The short X.Y version.
8181
version = release.rsplit(".", 1)[0]

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "django-declarative-apis"
7-
version = "0.34.0" # set by bumpversion
7+
version = "0.34.1" # set by bumpversion
88
description = "Simple, readable, declarative APIs for Django"
99
readme = "README.md"
1010
dependencies = [

tests/resources/test_emitters.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -109,15 +109,6 @@ def test_decode(self):
109109
resp = em.render(django.test.RequestFactory().get("/"))
110110
self.assertEqual(json.loads(resp), ["foo", "bar"])
111111

112-
def test_decode_empty_list(self):
113-
em = emitters.JSONEmitter([""], lambda: None)
114-
resp = em.render(django.test.RequestFactory().get("/"))
115-
self.assertEqual(resp, "")
116-
117-
em = emitters.JSONEmitter([], lambda: None)
118-
resp = em.render(django.test.RequestFactory().get("/"))
119-
self.assertEqual(resp, "")
120-
121112

122113
class DjangoEmitterTestCase(unittest.TestCase):
123114
def test_render_http_response_succes(self):

tests/resources/test_resource.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import django.test
1414
from django.test.utils import override_settings
1515
from unittest import mock
16+
from django.http import HttpResponse
1617

1718
from django_declarative_apis.authentication.oauthlib import oauth_errors
1819
from django_declarative_apis.resources import resource
@@ -212,3 +213,23 @@ def test_email_exception(self):
212213
(subj, body, _, __), ___ = mock_email.call_args_list[0]
213214
self.assertEqual(subj, "[Django] Django Declarative APIs crash report")
214215
self.assertEqual(body, traceback)
216+
217+
def test_call_no_content_response(self):
218+
"""Test that HTTP 204 responses return empty content with content-length 0"""
219+
220+
def handle_delete(request, *args, **kwargs):
221+
# Handler returns an HttpResponse with 204 status as the result
222+
return http.HTTPStatus.OK, HttpResponse(status=http.HTTPStatus.NO_CONTENT)
223+
224+
class Handler:
225+
allowed_methods = ("DELETE",)
226+
method_handlers = {"DELETE": handle_delete}
227+
228+
req = self.create_request(method="DELETE")
229+
res = resource.Resource(lambda: Handler())
230+
resp = res(req)
231+
232+
# Verify the response has 204 status and empty content
233+
self.assertEqual(resp.status_code, http.HTTPStatus.NO_CONTENT)
234+
self.assertEqual(resp.content, b"")
235+
self.assertEqual(len(resp.content), 0)

0 commit comments

Comments
 (0)