-
Notifications
You must be signed in to change notification settings - Fork 9
Add spec for Long custom scalar type
#26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
The `Long` data type is commonly used in many applications because the largest value that can be held in an `Int` value is `2^31-1`. See: graphql/graphql-spec#73
martinbonnin
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for looking into this.
I left a few comments mainly FYI. Feel free to use them or reject them, this repo is made so that we don't have all to agree. Just resolve the comments you reject so we can know when to merge this.
| For input both IntValue and StringValue shall be accepted so long as the StringValue is a base-10 representation of a | ||
| valid value within the range. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason why you accept string values here? This is not allowed for Int so this feels inconsistent.
| For input both IntValue and StringValue shall be accepted so long as the StringValue is a base-10 representation of a | |
| valid value within the range. | |
| Inputs should be a `number` between `-2^63` and `2^63-1`. That number must not have a fractional or exponential part. A leading `-` is added to represent negative values. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm really on the fence w.r.t. String. On the one hand, Javascript's number doesn't accurately represent the full range of the spec, and Javascript is one of, if not the most, used language for GraphQL. On the other hand it seems weird to allow string values, especially if they aren't allowed in both the input and output. If string values are not allowed, then all Javascript implementations of the spec will have to have special handling of the incoming JSON, assuming JSON is used for (de)serialization, to avoid issues where JSON.parse incorrectly parses the number.
E.g. https://codesandbox.io/p/devbox/lr8z8x
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know that Javascript now supports BigInt, but I don't know how widely adopted it is. And either way, JSON.parse doesn't parse a JSON number into BigInt (how could it, number can have fractional parts)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is clear that Long needs to support string values because JSON numbers are not guaranteed to support the range required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@andimarek JSON supports numbers with arbitrary precision:
JSON can contain number literals of arbitrary precision. However, it is not possible to represent all
JSON numbers exactly in JavaScript, because JavaScript uses floating point representation which
has a fixed precision.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oerall, I think JavaScript is mostly irrelevant here? Input values are either:
- GraphQL IntValue litteral (parameter values in executable documents): supports arbitrary precision
- JSON number litteral (json variables in the request): supports arbitrary precision
Is the concern about programmatically provided values?
I would leave this out of the scalar specs and up to the implementations. This is not something that goes over the wire and I'm fine leaving this unspecified.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I am reading over the guidelines again I notice the following:
Additionally, the input coercion should be liberal in what it accepts, while the result coercion should be much more restricted and never produce different JSON values for logically identical values. For example a MyLocalDate scalar could accept the literals "01-10-2022" and "01102022" as input for the first of October 2022, but the result coercion should always return one of the possible representations.
Given these are still the guidelines I propose we keep the spec such that it allows string or number for input coercion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I disagree with the guideline and will make a separate PR to open that discussion (edit: here). The robustness principle was a thing in the eighties but these days, it's generally considered harmful, there's even a RFC about it.
Ultimately, this is your place and we don't have to agree. Feel free to resolve this discussion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the spec is better off just allowing numbers. However, I was trying to figure out why I decided to include string as acceptable input originally. I believe the following factors were part of my original decision
- The current guide lines as quoted above
- The fact that Javascript doesn't play nicely with the entire range out of the box when deserializing JSON
- Related to the above, and purely selfish, we currently use
Stringto represent this data type in our own custom Scalar
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@benjie convinced me in that comment that we need strings and we can't completely ignore JS.
JSON number is better from a wire point of view but JSON.parse() is going to lose precision and it's not like we can change that or ask users to embed their own JSON parsers. (We could but I doubt it will be well received...)
I'm now team "let's require strings in both directions", same as what @benjie is suggesting in his comment I think.
Co-authored-by: Martin Bonnin <martin@mbonnin.net>
Co-authored-by: Martin Bonnin <martin@mbonnin.net>
This makes the wording more consistent and removes all references to JSON.
There's a separate suggestion to update the guide lines to not mention being liberal in what is accepted for inputs. See: graphql#40
|
Though it makes sense to use Using a numeric format when serializing to JSON would make programming languages which don't have native support for parsing arbitrarily long numbers in JSON have to use a custom JSON parser for all payloads sent using the most common HTTP encoding. That's not really viable, and will result in few people adopting Long. Instead, I'd recommend that you require string in both directions, at least for JSON. Note this text from the spec:
Serializing to string is perfectly valid, and is a safe fallback for basically everything. Even binary can serialize as string via base64/etc. |
The
Longdata type is commonly used in many applications because the largest value that can be held in anIntvalue is2^31-1. See: graphql/graphql-spec#73I'm honestly torn about whether or not output strings should be allowed 👀 . As discussed in the linked issue common clients (JavaScript) does not read JSON numbers above
2^53-1intonumberwithout loss of precision.Also accepting
Stringinputs without acceptingStringoutputs seem inconsistent.