What is the accepted way to send 64-bit values over JSON?

There is in fact a limitation at JavaScript/ECMAScript level of precision to 53-bit for integers (they are stored in the mantissa of a “double-like” 8 bytes memory buffer). So transmitting big numbers as JSON won’t be unserialized as expected by the JavaScript client, which would truncate them to its 53-bit resolution.

> parseInt("10765432100123456789")
10765432100123458000

See the Number.MAX_SAFE_INTEGER constant and Number.isSafeInteger() function:

The MAX_SAFE_INTEGER constant has a value of 9007199254740991. The
reasoning behind that number is that JavaScript uses double-precision
floating-point format numbers as specified in IEEE 754 and can only
safely represent numbers between -(2^53 - 1) and 2^53 - 1.

Safe in this context refers to the ability to represent integers
exactly and to correctly compare them. For example,
Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2 will
evaluate to true, which is mathematically incorrect. See
Number.isSafeInteger() for more information.

Due to the resolution of floats in JavaScript, using “64-bit floating point numbers” as you proposed would suffer from the very same restriction.

IMHO the best option is to transmit such values as text. It would be still perfectly readable JSON content, and would be easy do work with at JavaScript level.

A “pure string” representation is what OData specifies, for its Edm.Int64 or Edm.Decimal types.

What the Twitter API does in this case, is to add a specific ".._str": field in the JSON, as such:

{
   "id": 10765432100123456789,           // for JSON compliant clients
   "id_str": "10765432100123456789",     // for JavaScript
    ...
}

I like this option very much, since it would be still compatible with int64 capable clients. In practice, such duplicated content in the JSON won’t hurt much, if it is deflated/gzipped at HTTP level.

Once transmitted as string, you may use libraries like strint – a JavaScript library for string-encoded integers to handle such values.

Update: Newer versions of JavaScript engines include a BigInt object class, which is able to handle more than 53-bit. In fact, it can be used for arbitrarily large integers, so a good fit for 64-bit integer values. But when serializing as JSON, the BigInt value will be serialized as a JSON string – weirdly enough, but for compatibility purposes I guess.

Leave a Comment