I would like to denote decimal with 2 places and decimal with 1 place in my api documentation. I'm using swagger 2.0, Is there inbuilt defined type or any other 'round' parameter in the specs, or my only option is to use 'x-' extension?
OpenAPI (fka Swagger) Specification uses a subset of JSON Schema to describe the data types.
If the parameter is passed as a number, you can try using multipleOf as suggested in this Q&A:
type: number
multipleOf: 0.1 # up to 1 decimal place, e.g. 4.2
# multipleOf: 0.01 # up to 2 decimal places, e.g. 4.25
Hovewer, multipleOf validation against floating-point numbers can be unreliable due to floating-point math specifics.
If your number if passed as a string, you can specify a regex pattern for the desired number format:
type: string
pattern: your_regex
In any case, you can also document any restrictions verbally in the description.
Related
In openapis.org OpenAPI 3.0(https://spec.openapis.org/oas/v3.1.0), I am unable to find maxLength keyword to denote the max length allowed for a datatype nor an alternate. Can anyone help, do I need to do it with x-?
It's tricky to find it:
4.4 Data Types :
As defined by the JSON Schema Validation vocabulary, data types can have an optional modifier property: format. OAS defines additional formats to provide fine detail for primitive data types.
JSON Schema Validation:
This document contains the description for maxLength
6.3.1. maxLength
The value of this keyword MUST be a non-negative integer.
A string instance is valid against this keyword if its length is less
than, or equal to, the value of this keyword.
The length of a string instance is defined as the number of its
characters as defined by RFC 8259 [RFC8259].
It's easier to find the documentation in OpenAPI Version 3.0.3
I can't find a sample of currency data type in the object definition, nor a document on the subject.
There is no built-in "currency" type. You would typically use type: number with an optional format modifier to indicate the meaning of the numeric type:
type: number
format: currency
format can have arbitrary values, so you can use format: currency or format: decimal or whatever your tool supports. Tools that recognize the given format will map the value to the corresponding type.
The type in the OpenAPI 2.0 standard closest to typical decimal dollar values seems to be type number, format float, which is a 32-bit floating point format (see other online discussions such as here)
I'm going to create an API which contains money amounts. I was wondering what the best practices are, or whether someone has some good or bad experiences with certain formats.
should we transmit base units or minor units? (amount vs amount_cents)
should we represent the numbers as integers / decimals or as strings?
I've seen the following two possibilities:
send amounts as a string like so: "5.85" (a string with base units)
send amounts in their minor unit: 585 (an integer which expresses the amount in the minor unit)
I'm going back and forth between those two. So I went out to check what other APIs use and came up with the following list:
Stripe: integer with minor units
Braintree: string with base units
Google Wallet: string with base units
Paypal: string with base units
Amazon Payments: string with base units
The Currency Cloud: string with base units
2checkout: string with base units
Adyen: integer with minor units
Dwolla: decimal with base units
GotoBilling: weird heuristics! "Amount may be formatted with or without a decimal. If no decimal is given two (2) decimal places are assumed (1.00 = 100)"
GoCardless: string with base units
Intuit: decimal with base units in requests, string with base units in responses
Klarna: integer with minor units
MasterCard: integer with minor units
Paynova: string with base units
Rogers Catalyst: string with base units
WePay: string with base units
Venmo: decimal with base units
So, out of 18 sampled APIs, 4 are using minor units, 13 are using base units and 1 is using a hard-to-comprehend mixture. And within the 13 who use base units, 10 are transmitting them as quoted strings, 3 as unquoted decimals (actually 2 and a half if you look at Intuit).
I personally feel uncomfortable having to parse a string like "8.20", because if you parse this it becomes "8.19999999..." if you make the mistake to use floats. So I'm leaning towards sending integers only. But I don't think this is a great argument, and I see that generally APIs tend to go with base units as strings.
Do you have any good arguments for/against each format?
Integers will eat the dot, that's one less byte :D Integers will have a max_int, do you have anyone rich enough that may overflow?
People that will parse a currency string as float will turn the int to float anyway.
If you send binary data, integer will be much smaller than a string and the way to go. If you send xml anyway, you might as well define it a string (the file is probably compressed before sending right?), try to make it "currency" type as opposed to listing it as a full string though.
Which datatype is the best depends on your usage. For calculations integers or doubles are going to be faster, skipping the parsing step.
If sending the data through networks is your goal you're better off with strings.
That said, any functionality should be realizable using either method.
-:total_cost_with_tax => #<BigDecimal:7fda9d17aaf0,'0.105225E4',18(45)>,
-:total_cost_without_tax => #<BigDecimal:7fda9d17b450,'0.972E3',9(36)>,
-:total_last_installment_amount => #<BigDecimal:7fda9d17b978,'0.8011E2',18(45)>,
-:total_monthly_installment_amount => #<BigDecimal:7fda9d17abb8,'0.8011E2',18(45)>,
-:total_tax => #<BigDecimal:7fda9d17b068,'0.8025E2',18(45)>,
+:total_cost_with_tax => #<BigDecimal:7fda9d0184c8,'0.105225E4',18(36)>,
+:total_cost_without_tax => #<BigDecimal:7fda91ff2b48,'0.972E3',9(27)>,
+:total_last_installment_amount => #<BigDecimal:7fda91fee548,'0.8011E2',18(36)>,
+:total_monthly_installment_amount => #<BigDecimal:7fda91fe72c0,'0.8011E2',18(36)>,
+:total_tax => #<BigDecimal:7fda9d00a2b0,'0.8025E2',18(36)>,
So, these are littered throughout some of my tests... rspec 2, rails 3. I'm comparing hashes using .should eq() to compare. I can't seem to get the incantation right. Seems like it's a precision thing, which seems silly.
RSpec 3 has BigDecimal eq:
x.should eq(y)
expect(x).to eq(y)
If you're comparing a BigDecimal to a Float, be aware the precision can affect the comparison.
You can use this:
x.should be_within(delta).of(y)
expect x.to be_within(delta).of(y)
If you're comparing two BigDecimal numbers that have different precisions, be aware that these numbers can show different results from inspect and also from hash depending on your platform and what version of Ruby BigDecimal you're running.
For example, this can happen:
BigDecimal.new("2").hash == BigDecimal.new("2.0").hash
=> false
Your output shows that your BigDecimal string representations are slightly different.
Here's what your strings mean:
Part 1 is the object address.
Part 2 is the number value represented as a string.
Part 3 is the number of significant digits then the maximum number of significant digits.
Your output shows that your strings have different object addresses, identical number values (i.e. part 2), identical significant digits (the first number in part 3), but different numbers of maximum significant digits.
For your question, using RSpec 2 and comparing BigDecimal hashes, you'll solve your issue by using the rspec be_within matcher.
Note that Ruby BigDecimal numbers and Float numbers are both floating point numbers:
A BigDecimal is a arbitrary-precision decimal floating point number.
A Float is the native architecture's double-precision binary floating point number.
You can see the BigDecimal decimal floating-point representation by doing this:
require 'bigdecimal'
x=BigDecimal.new(100)
=> #<BigDecimal:7f8e62038570,'0.1E3',9(27)>
The significand part is '0.1' and the exponent part is 'E3'.
Note that this is for the typical Ruby MRI/KRI VM. Implementations may be different on other Ruby VMs, such as JRuby, because Java has its own bignum code.
When you compare two different types of floating-point numbers, such as BigDecimal and Float, you can get results that may seem counter-intuitive because the types use different bases (decimal vs. binary), different precisions, and different Ruby classes.
Example:
BigDecimal.new("1.111111111111111") === 1.111111111111111
=> true
BigDecimal.new("1.1111111111111111") === 1.1111111111111111
=> false
With Rspec 3.x you can use for BigDecimal the eq matcher like you can use it for float.
RSpec.describe "an integer" do
it "is equal to a float of the same value" do
expect(5).to eq(5.0)
end
end
For more information see the RSpec documentation:
https://www.relishapp.com/rspec/rspec-expectations/v/3-4/docs/built-in-matchers/equality-matchers
Using C++ APIs, how can you extract the decimal value of a bit-vector constant from a model.
There are several C-Functions that allow you to extract different types of values, depending on the expected size of the numerals: Z3_get_numeral_int, Z3_get_numeral_uint, Z3_get_numeral_uint64, Z3_get_numeral_int64. For numbers that don't fit into those basic types, we can use the Z3_get_numeral_string function to get a string representation that can be parsed into your preferred big-int representation.
Note that these functions are C-functions, not C++ functions, but those two APIs mix nicely. (See e.g, also z3 C++ API & ite).