Sorry if this has already been debated, but I found nothing in my searches.
What's your take on this? I see two possible issues when processing JSON
representations that contain money amounts:
1. loss of precision due to floating-point arithmetic (really? see below)
2. big numbers
I've been looking for prior art on this and both Stripe and
Amiando represent money amounts using JSON numbers encoded as the
smallest subdivision of the respective currency. For example 123 dollars
means 1 dollar and 23 cents. That's a well know technique for avoiding
loss of precision.
The Open Exchange Rates API on the other hand uses the decimal
notation for JSON numbers in order to represent exchange rates.
1. use JSON numbers, decimal notation
2. use JSON numbers, integer notation, encoded in smallest monetary
3. use JSON strings, decimal notation
4. use JSON strings, integer notation, encoded in smallest monetary
Now back to the issues:
1. Loss of Precision
I don't think there's any peril here if you consider just the parsing
phase. Amounts have at most 3 decimal digits (right?) and arithmetic
operations are not allowed in the JSON format. So, it should be safe to
parse a JSON number in decimal notation.
The real issue comes when the developer has no idea that floating point
arithmetic is bad when dealing with monetary amounts. She'll find it
convenient to parse those values as floats (because that's probably the
default in her JSON parsing library) and then perform arithmetic
operations on them.
Having the amount represented as an integer would probably serve as a
good warning sign to the developer that integrates the API. Well... at
least maybe she'll ask the reason for the weird choice of representation.
2. Big Numbers
The JSON standard does not impose restrictions on the size of numbers.
It can be as large as it gets, but most parsers will certainly default
have built-in support for big ints or decimals, so the standardized
`JSON.parse` utility will parse to the built-in number type, which is
always a double).
In the end JSON numbers are just strings without quotes, so an
alternative library, or even some minor pre-processing before parsing,
can be used to alleviate this issue. Also, some domains don't have this
problem because it's hard to find such a huge amount of money (which is
why I believe Stripe went this way).
Mine at least... For the API I build I'll probably go with Stripe's
solution: JSON numbers, integer notation in smallest monetary
subdivision. Integer notation instead of decimal so that it'll be less
likely for a developer to do floating-point arithmetic (but not
unavoidable). JSON numbers instead of strings because it's unlikely to
have huge amounts.
Apologies for the long email. So, what do you think?
Ionuț G. Stan | http://igstan.ro