Skip to content

Commit 4d4b5d1

Browse files
ericproulxclaude
andcommitted
Always format JSON via Grape::Json.dump
Grape::Formatter::Json and Grape::Formatter::SerializableHash short-circuited to object.to_json whenever the object responded to it. Since nearly every object responds to to_json, Grape::Json.dump was effectively never reached and a configured multi_json back-end (e.g. oj) was bypassed during formatting. Remove the to_json short-circuit so both formatters always serialize through Grape::Json.dump, honoring the JSON back-end consistently with Grape::ErrorFormatter::Json and Grape::Parser::Json. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 6995daf commit 4d4b5d1

5 files changed

Lines changed: 10 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#### Fixes
88

9+
* [#2769](https://github.com/ruby-grape/grape/pull/2769): Always format JSON via `Grape::Json.dump` so a configured `multi_json` back-end is honored - [@ericproulx](https://github.com/ericproulx).
910
* Your contribution here.
1011

1112
### 3.3.0 (2026-06-20)

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3160,7 +3160,7 @@ end
31603160

31613161
Built-in formatters are the following.
31623162

3163-
* `:json`: use object's `to_json` when available, otherwise call `MultiJson.dump`
3163+
* `:json`: serializes the object via Grape's JSON back-end (`JSON` by default, or `multi_json` when available)
31643164
* `:xml`: use object's `to_xml` when available, usually via `MultiXml`
31653165
* `:txt`: use object's `to_txt` when available, otherwise `to_s`
31663166
* `:serializable_hash`: use object's `serializable_hash` when available, otherwise fallback to `:json`

UPGRADING.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
Upgrading Grape
22
===============
33

4+
### Upgrading to >= 4.0
5+
6+
#### The `:json` and `:serializable_hash` formatters no longer call `to_json`
7+
8+
`Grape::Formatter::Json` and `Grape::Formatter::SerializableHash` previously short-circuited to `object.to_json` whenever the object responded to it. Since virtually every object responds to `to_json`, this meant `Grape::Json.dump` was effectively never reached and a configured `multi_json` back-end (e.g. `oj`) was bypassed during formatting. Both formatters now always serialize through `Grape::Json.dump`, so the JSON back-end is honored consistently (matching `Grape::ErrorFormatter::Json` and `Grape::Parser::Json`).
9+
10+
If you relied on a custom `to_json` for response formatting, either register your own formatter or make `Oj.mimic_JSON` (or your serializer of choice) the active back-end.
11+
412
### Upgrading to >= 3.3
513

614
#### Minimum required Ruby is now 3.3

lib/grape/formatter/json.rb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ module Grape
44
module Formatter
55
class Json < Base
66
def self.call(object, _env)
7-
return object.to_json if object.respond_to?(:to_json)
8-
97
::Grape::Json.dump(object)
108
end
119
end

lib/grape/formatter/serializable_hash.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ class << self
77
def call(object, _env)
88
return object if object.is_a?(String)
99
return ::Grape::Json.dump(serialize(object)) if serializable?(object)
10-
return object.to_json if object.respond_to?(:to_json)
1110

1211
::Grape::Json.dump(object)
1312
end

0 commit comments

Comments
 (0)