lostisland / faraday_middleware

Various Faraday middlewares for Faraday-based API wrappers
MIT License
557 stars 203 forks source link

Use JSON.generate instead of .dump in request middleware #266

Closed Be-ngt-oH closed 3 years ago

Be-ngt-oH commented 3 years ago

The standard library's JSON gem provides two methods for encoding objects as JSON strings JSON.dump and JSON.generate.

To quote the docs, JSON.load is "is part of the implementation of the load/dump interface of Marshal and YAML.". It uses JSON.generate but calls it with a different set of options.

Analogous there is JSON.load and JSON.parse where JSON.load must not be used with untrusted user input. Typically, dump gets paired with load and generate with parse

Since we want to encode a hash as a JSON string, it makes sense to use JSON.generate rather than dump. This ensures that safe defaults will be used. The differences (default options) are as follows:

JSON.dump JSON.generate
max_nesting false 100
allow_nan true false

The max_nesting option set will ensure that no infinite loop can happen if there's circular references in the data which might be a breaking change if users are creating deeply nested JSON objects. A workaround is to not pash a hash to Faraday but instead encode it, e.g. with an increased max_nesting value, beforehand.

The allow_nan option causes JSON generation to fail if NaN, Infinity or -Infinity is encountered, e.g. JSON.generate({a: 0.0/0}) raises NaN not allowed in JSON (JSON::GeneratorError) which seems to be a sane default.


Background story how we came to notice this:

We recently ran into an odd issue with a Rails app using the Oj gem1. As of Oj version 3.11.3 there is a difference in behaviour between JSON.generate and JSON.dump. This is the output from a console in a fresh Rails app:

JSON.dump(Time.now)
=> "\"2021-04-13 16:25:23 +0100\""
JSON.generate(Time.now)
=> "\"2021-04-13T16:25:27.154+01:00\""

Because of another gem that was using Faraday Middleware internally this caused timestamps in the wrong format when generating the JSON for an external API.

olleolleolle commented 3 years ago

@Be-ngt-oH 👋 Hello! I made some linting fixes, and also, made the CI quicker, so that we can see you changes go green.