CBOR Tag for JSON Number Strings
For a side project, I’m converting JSON inputs to CBOR, or Concise Binary
Object Representation, defined by RFC 8949, in order to store a more compact
representation in the database. This go Go app uses encoding/json package’s
UseNumber decoding option to preserve numbers as strings, rather tha
float64s. Alas, CBOR has no support for such a feature, so such values
cannot survive a round-trip to CBOR and back, as demonstrating by this example
using the github.com/fxamacker/cbor package (playground)
|
|
The output:
{"temp":"98.6"}
Note that the input on line 2 contains the number 98.6, but once the value
has been transformed to CBOR and back it becomes the string "98.6".
I wanted to preserve JSON numbers treated as strings. Fortunately, CBOR uses
numeric tags to identify data types, and includes a registry maintained by
IANA. I proposed a new tag for JSON numbers as strings and, through a few
iterations, the CBOR group graciously accepted the formal description of
semantics and assigned tag 284 in the registry.
Now any system that handles JSON numbers as strings can use this tag to preserve the numeric representation in JSON output.
Here’s how to use the tag customization features of
github.com/fxamacker/cbor to transparently round-trip json.Number values
playground:
|
|
Lines 1-16 contain the main difference from the previous example. They create
a CBOR encoder (em) and decoder (dm) with tag 284 assigned to
json.Number values. The code then uses them rather than the cbor package
to Marshal and Unmarshal the values on lines 28 and 35. The result:
{"temp":98.6}
Et voilà! json.Number values are once again preserved.
I believe these custom CBOR encoder and decoder configurations bring full
round-trip compatibility to any regular JSON value decoded by encoding/json.
The other important config for that compatibility is the DefaultMapType
decoding option on line 15, which ensures maps use string values for map
keys rather the CBOR-default any values.