3
votes

I'm trying to define a JSON schema for a property

money: 12.12

My main concern is that a maximum of 2 decimal places should be allowed. My initial attempt at defining this field was

money: {
  type: 'number',
  minimum: 0,
  multipleOf: 0.01
}

However, owing to floating point imprecision this fails. For example, using the tv4 validator, the number 147.41 passes validation, but 147.42 fails. Is there an alternative way to define a numeric type which will only allow a maximum of 2 decimal places?

It seems that the purpose of the "format" attribute is to implement these types of restrictions, but if I define the field like so:

money: {
  type: 'number',
  format: 'currency',
  minimum: 0
}

Then how do I specify that fields with a 'currency' format should only allow up to 2 decimal places?

2
The question being asked here seems more like "How to enforce two decimal places for currency numbers?". The title of this question "Defining a JSON schema currency type" has a better answer here: stackoverflow.com/q/30249406/27581Michael Kropat

2 Answers

5
votes

I dislike the integer value thing, I find it doesn't solve real issues when it comes to proper number rounding when things like percentages get involved, (which is why other languages have Decimal types) and wanted to offer this very simple solution using string and pattern:

"amount":{
    "type": "string",
    "pattern": "^(0|([1-9]+[0-9]*))(\.[0-9]{1,2})?$",
    "minLength": 1,
    "description": "A Monetary Amount",
    "examples": [
        "0",
        "0.00",
        "0.05",
        "19.95",
        "255.5",
        "120000"
    ]
}

You can remove the minLength if you don't want it.

2
votes

Your best option is likely to multiply your currency values by 100. Then you have whole numbers, and validation should work fine. In general, using floating point to store monetary values is a bug farm, so you're better off moving toward "integers" even if technically they are still floating point values in JSON.

Some systems use an ISO currency code with the third letter in lower case to denote such currencies. For example GBp for British pence, or USd for US pennies. See https://stackoverflow.com/a/30635729/4323