From 16da5172a85c707ccd6c38451cdbad7c218469ea Mon Sep 17 00:00:00 2001 From: Demian Brecht Date: Tue, 22 Jul 2025 11:46:39 -0700 Subject: [PATCH 1/4] fix json emitter for empty response bodies --- django_declarative_apis/resources/emitters.py | 18 +++++++++++------- tests/resources/test_emitters.py | 5 +++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/django_declarative_apis/resources/emitters.py b/django_declarative_apis/resources/emitters.py index 71b8925..fd50d4e 100644 --- a/django_declarative_apis/resources/emitters.py +++ b/django_declarative_apis/resources/emitters.py @@ -183,19 +183,23 @@ def decode(self, data): def render(self, request): cb = request.GET.get("callback", None) assert cb is None, "JSONP Callbacks not suppoted" - seria = json.dumps( - self.decode(self.construct()), - cls=DjangoJSONEncoder, - ensure_ascii=False, - indent=4, - ) + seria = self.decode(self.construct()) + if isinstance(seria, list): + if len(seria) == 0 or (len(seria) == 1 and len(seria[0]) == 0): + # the body is empty, no need to run json.dumps + return "" # Callback # TODO: do we care about JSONP? # if cb and is_valid_jsonp_callback_value(cb): # return '%s(%s)' % (cb, seria) - return seria + return json.dumps( + seria, + cls=DjangoJSONEncoder, + ensure_ascii=False, + indent=4, + ) Emitter.register("json", JSONEmitter, "application/json; charset=utf-8") diff --git a/tests/resources/test_emitters.py b/tests/resources/test_emitters.py index e591b30..3aba3f4 100644 --- a/tests/resources/test_emitters.py +++ b/tests/resources/test_emitters.py @@ -109,6 +109,11 @@ def test_decode(self): resp = em.render(django.test.RequestFactory().get("/")) self.assertEqual(json.loads(resp), ["foo", "bar"]) + def test_decode_empty_list(self): + em = emitters.JSONEmitter([""], lambda: None) + resp = em.render(django.test.RequestFactory().get("/")) + self.assertEqual(resp, "") + class DjangoEmitterTestCase(unittest.TestCase): def test_render_http_response_succes(self): From 91dd39dd3cb8e6576985e70cd57fc82e6194bbcc Mon Sep 17 00:00:00 2001 From: Demian Brecht Date: Tue, 22 Jul 2025 12:13:07 -0700 Subject: [PATCH 2/4] Update django_declarative_apis/resources/emitters.py Co-authored-by: bgrant --- django_declarative_apis/resources/emitters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django_declarative_apis/resources/emitters.py b/django_declarative_apis/resources/emitters.py index fd50d4e..f26da52 100644 --- a/django_declarative_apis/resources/emitters.py +++ b/django_declarative_apis/resources/emitters.py @@ -182,7 +182,7 @@ def decode(self, data): def render(self, request): cb = request.GET.get("callback", None) - assert cb is None, "JSONP Callbacks not suppoted" + assert cb is None, "JSONP Callbacks not supported" seria = self.decode(self.construct()) if isinstance(seria, list): if len(seria) == 0 or (len(seria) == 1 and len(seria[0]) == 0): From fe2c91fffc4841d710788b8ebb733d95f83a268f Mon Sep 17 00:00:00 2001 From: Demian Brecht Date: Tue, 22 Jul 2025 12:22:28 -0700 Subject: [PATCH 3/4] pr feedback --- tests/resources/test_emitters.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/resources/test_emitters.py b/tests/resources/test_emitters.py index 3aba3f4..6bd304f 100644 --- a/tests/resources/test_emitters.py +++ b/tests/resources/test_emitters.py @@ -114,6 +114,10 @@ def test_decode_empty_list(self): resp = em.render(django.test.RequestFactory().get("/")) self.assertEqual(resp, "") + em = emitters.JSONEmitter([], lambda: None) + resp = em.render(django.test.RequestFactory().get("/")) + self.assertEqual(resp, "") + class DjangoEmitterTestCase(unittest.TestCase): def test_render_http_response_succes(self): From aef8eb946fcec90fd607d092364ed9cfdf742d52 Mon Sep 17 00:00:00 2001 From: Demian Brecht Date: Tue, 22 Jul 2025 12:31:33 -0700 Subject: [PATCH 4/4] changelog update, version bump --- .bumpversion.cfg | 2 +- CHANGELOG.md | 3 +++ docs/source/conf.py | 2 +- pyproject.toml | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 93a68e6..32d37c1 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.33.0 +current_version = 0.34.0 [bumpversion:file:pyproject.toml] diff --git a/CHANGELOG.md b/CHANGELOG.md index 08cf8df..553a07d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 # [Unreleased] +# [0.34.0] +- [PR 178](https://github.com/salesforce/django-declarative-apis/pull/178) Fix JSONEmitter for empty response bodies. + # [0.33.0] - [PR 170](https://github.com/salesforce/django-declarative-apis/pull/170) Update publish workflow - [PR 173](https://github.com/salesforce/django-declarative-apis/pull/173) handle request.GET or request.POST being None + a few other improvements diff --git a/docs/source/conf.py b/docs/source/conf.py index e21a2a3..9ec3d8e 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -75,7 +75,7 @@ # built documents. # The full version, including alpha/beta/rc tags. -release = "0.33.0" # set by bumpversion +release = "0.34.0" # set by bumpversion # The short X.Y version. version = release.rsplit(".", 1)[0] diff --git a/pyproject.toml b/pyproject.toml index 0c1e37c..544a417 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "django-declarative-apis" -version = "0.33.0" # set by bumpversion +version = "0.34.0" # set by bumpversion description = "Simple, readable, declarative APIs for Django" readme = "README.md" dependencies = [