Openapi-specification: Support for Decimal (monetary) data

Created on 2 Apr 2018  路  16Comments  路  Source: OAI/OpenAPI-Specification

Related to: https://github.com/OAI/OpenAPI-Specification/issues/1517

Here is a printout from Open Banking in the UK. "Amount" is the field of interest.

HTTP/1.1 200 OK
x-fapi-interaction-id: 93bac548-d2de-4546-b106-880a5018460d
Content-Type: application/json

{
  "Data": {
    "DirectDebit": [
      {
        "AccountId": "22289",
        "DirectDebitId": "DD03",
        "MandateIdentification": "Caravanners",
        "DirectDebitStatusCode": "Active",
        "Name": "Towbar Club 3 - We Love Towbars",
        "PreviousPaymentDateTime": "2017-04-05T10:43:07+00:00",
        "PreviousPaymentAmount": {
          "Amount": "0.57",
          "Currency": "GBP"
        }
      }
    ]
  },
  "Links": {
    "Self": "https://api.alphabank.com/open-banking/v2.0/accounts/22289/direct-debits/"
  },
  "Meta": {
    "TotalPages": 1
  }
}

Most helpful comment

@cyberphone Yes. Here is the ANBF grammar for how to serialize a JSON Number over the wire in UTF-8 text.

And your last comment gets to the heart of the matter. OpenAPI is not in the business of telling people how to serialize data. That is the job of media type specifications. We are in the business of trying to describe in a platform independent manner what people chose to do.

All 16 comments

In that example, amount appears to be a string type.

I would rather say it is _mapped_ to a string because there is no Decimal type in JSON in the same way as there is no DateTime type either.

W3C's Payment Request uses the same approach:
https://www.w3.org/TR/payment-request/#paymentcurrencyamount-dictionary

AFAICT, this is the de-facto standard for JSON and "money"/Decimal.

And the actual issue with the OpenAPI specification is?

Adding support for the Decimal/monetary data type.

My current implementation:

/**
 * Read a BigDecimal property.<p>
 * Note: Since JSON does not support a native BigDecimal type, 
 * this method builds on <i>mapping</i>.</p>
 * @param name Property
 * @param decimals Required number of fractional digits or <b>null</b> if unspecified
 * @return Java <code>BigDecimal</code>
 * @throws IOException For syntax errors
 * @see JSONObjectWriter#setBigDecimal(String, BigDecimal, Integer)
 */
public BigDecimal getBigDecimal(String name, Integer decimals) throws IOException {
    return parseBigDecimal(getString(name), decimals);
}

The Decimal data type usually do not support "Scientific" notation.

Do you mean as a new type (which would not be supported by JSON or JSON schema) or as a new format?

I mean something along the lines of dateTime which I guess is a predefined OpenAPI data type.

Your use of the words "I guess" does worry me slightly. Can I ask you to read the sections of the spec related to data types and formats if you have not already done so?

Sure, I'm unarguable NOT an expert on OpenAPI and JSON Schema. I did though read the table of data types: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#data-types
I found dateTime and saw that it is mapped into RFC3339 formatted "strings".

I would reuse that idea for Decimal unless there is something fundamentally wrong with doing that. The W3C folks' format specification would probably suffice.

@cyberphone Yes, the specification suggests to use the format date-time along with type string to represent the common language type DateTime. Adding a new format for decimal that could be applied to the underlying type string is definitely something we would consider adding to the format registry. But I would also say that it would be perfectly valid to have a description that said type: number and format: decimal. The type is indicating what native JSON Schema type has been chose for the wire format, and format property is layering some additional semantics onto that assist tooling with the translation.

@cyberphone suport for decimals as strings, which would be implemented as {"type": "string", "format": "decimal"} or something very similar (because there is no way to control the relevant behavior as a JSON number) is proposed as https://github.com/json-schema-org/json-schema-spec/issues/361

It is literally waiting for someone who has knowledge of this area to be willing to write a PR. No one objects to it, but I'm sure there are subtleties here so I'm not comfortable writing a PR for it. Sadly, very few other people volunteer to write PRs for JSON Schema.

I would love to also have {"type": "number", "format": "decimal"} as an option if a reasonable spec can be written that works with the data model and not with the JSON text. As noted repeatedly, JSON is specified on a data model, not on JSON text (or octet stream or however you want to think about it).

@darrelmiller For me who is neither an expert on OpenAPI nor on JSON Schema, but rather "fluent" in JSON, do you mean that you would consider using JSON Number as wire format? I would check that with tool vendors before putting that in concrete. The three (individually created) examples I provided, all took the JSON String path. There is probably a reason for that.

@cyberphone Yes. Here is the ANBF grammar for how to serialize a JSON Number over the wire in UTF-8 text.

And your last comment gets to the heart of the matter. OpenAPI is not in the business of telling people how to serialize data. That is the job of media type specifications. We are in the business of trying to describe in a platform independent manner what people chose to do.

@darrelmiller Your colleges at the ".NET division" serializes a BigInteger as:

"myBigInteger":{"_bits":[1156841472,1164153218],"_sign":1}

Although maybe of limited interest to you, there is a JSON clear text signature specification in the workings which (for portability reasons), builds on I-JSON and ECMAScript serialization of JSON primitives:
https://tools.ietf.org/id/draft-erdtman-jose-cleartext-jws-00.html

The alternative to that is dressing the entire JSON object in Base64 which is making the "API" rather indirect.

Just to see that we are on the same page with respect to tool support. Standard integers like implemented in for example Java and C# have:

  • Different syntax compared to a Decimal
  • Different storage compared to a Decimal
  • Different numeric range compared to a Decimal

That is, Integer and Decimal cannot readily make use of the same decoder/parser.

To make this feasible Decimal must be identified as a distinct data type. I.e. "mapped".

Do you agree with the above?

If you do, we are talking about saving 2 bytes (the quotes) and keeping "purity" (aka data model).

Since _purity will only exist on the wire_, we are effectively down to the 2 byte issue. However, saving 2 bytes comes at a cost: limited compatibility with JavaScript as well as with existing practices for open systems.

The decision is yours.

Because we support the JSON data types only, this proposal is being tracked for adding a new format to the proposed OAS/JSON-Schema formats registry. See #845

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rocchisanijl picture rocchisanijl  路  5Comments

muhmud picture muhmud  路  5Comments

Prasanthmv picture Prasanthmv  路  4Comments

domenique picture domenique  路  4Comments

slinkydeveloper picture slinkydeveloper  路  4Comments