-
Notifications
You must be signed in to change notification settings - Fork 9
Remove paragraph about the robustness principle #40
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
There's a separate suggestion to update the guide lines to not mention being liberal in what is accepted for inputs. See: graphql#40
benjie
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.
Is removing this a breaking change?
🤔
I don’t think so.
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 wrote that paragraph and still think it is how Scalars should work.
I don't think this breaks any symmetry as there is no symmetry to begin with: I can have an runtime input value that is some language/code dependent format and then have an output in JSON. I still believe the output should be more restricted and produce always the same value regardless of the format produced.
It would also put unreasonable expectation onto Scalar implementations: for example an ID can take 1234 as input but it always produces a String value "1234" regardless of the input being "1234" or 1234. If you want to try to preserve not only the semantics of the value but the exact format you would have to consider that in the implementation which would make everything much more complicated.
@benjie I don't think it is.
@andimarek I think there is. For JSON, there is Or do you disagree there?
Not sure I get it. Do you have some sample code of that? I'm operating under the assumption that the Coercion will do "the good thing" regardless of the internal (Java/JS) value. |
|
To me the term "liberal" feels a bit out of place in a specification. Liberal to what extent? I find this opens more questions than it answers. It would probably be more useful to let the specifications for individual scalars precisely define what their acceptable input/output formats are. |
* Add spec for `Long` custom scalar type 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 * Update scalars/contributed/jakobmerrild/long.md Co-authored-by: Martin Bonnin <[email protected]> * Update scalars/contributed/jakobmerrild/long.md Co-authored-by: Martin Bonnin <[email protected]> * Update wording of Long spec This makes the wording more consistent and removes all references to JSON. * Update Long spec to not allow strings for input There's a separate suggestion to update the guide lines to not mention being liberal in what is accepted for inputs. See: #40 * Rewrite Long spec in terms of String encoding Ultimately, not every language can easily parse arbitrarily large JSON numbers. As such we are better off using a string serialization scheme which then allows the adaptors to use whichever methods they see fit to turn the string into a different representation after coercion, e.g. Long or BigInt * Update date of spec The recent changes represent a significant departure from the original spec, so we update the date :) * Fix formatting and spelling --------- Co-authored-by: Martin Bonnin <[email protected]>
|
@martinbonnin for example in GraphQL JS: https://github.com/graphql/graphql-js/blob/16.x.x/src/type/scalars.ts#L219 ID is always returned as String but it accepts also numbers. Same logic we have in GraphQL Java. |
|
201020022002 could mean 20th October 2002 at 8:02pm, or it could be May 15th 1976 at 2:53pm as a unix timestamp in milliseconds. Or it could be invalid 2010-20-02T20:02 (there’s no 20th month), or it could be 2010.20.02 in the old Kazakhstan yyyy.dd.mm format. Accepting broad input and applying our own heuristics to it is likely to result in subtle bugs in software, and doesn’t bring much value: why would someone want to format a date in that way? What problem are we trying to solve here? I think it’s much more likely that someone would submit a Unix timestamp than an all numbers formatted date with no separators. Ambiguity should error. ID is not ambiguous: you simply stringify the number and you’re done. Not so with dates. |
|
@andimarek thanks for providing that example. parseValue(inputValue) {
if (typeof inputValue === 'string') {
return inputValue;
}
if (typeof inputValue === 'number' && Number.isInteger(inputValue)) {
return inputValue.toString();
}
throw new GraphQLError(`ID cannot represent value: ${inspect(inputValue)}`);
},This is in line with what the GraphQL spec says: This is pretty much required by the spec in itself but if you ask me, that is a mistake and makes ID more complex than if ID were always a String. It was certainly the good choice in 2012 but I wouldn't apply the same design choices to new scalars being added in 2025. |
|
@benjie @martinbonnin let me try to explain more what my intention was behind this section. (and yes I agree the current section how it is worded is not very helpful and the example provided is not good either) The idea is to provide convenience to the user, while not be ambiguous. But the But it goes further than just literals, a Scalar also needs to convert language specific values at runtime and here the Scalar should also be designed to be flexible for the users convenience. For example in Java you should accept a String or an Again same in JS and But at the same time the output value of a Scalar should not produce different kind of values (for example sometimes a String or Integer for This is background of this section: trying to capture this asymmetry between input (literal and runtime values) and output by being flexible for the input for the user experiences sake, but being restricted for the output (again for the users experience sake). I hope that helps. |
|
@andimarek I disagree that input flexibility gives a better user experience. I personally dread having a choice. I curse at Gradle dozens of times a day just because there are so many ways to do the same thing. I value consistency and predictability.
Same for scalars. Do I need this Date to be a Strong typing also makes it easier to navigate a code base. And overall gives me better predictability and lower cognitive load. I get where you're coming from but I think there is value in strict scalars. It's 100% fine if some people want to have them lenient though. I would just not make it a recommendation. |
|
@martinbonnin I argue you should care, because you are designing a scalar/library for the users. The reality of users for example is that a An The python quote is not a bad or wrong per se, but we are not designing a closed system, but we are interfacing with other systems which we can't control or change. |
|
@andimarek I think we have to agree to disagree. As a library author, some of my users want lenient, others want strict. What audience to optimize for is a tradeoff and I don't think we (graphql community) should make this tradeoff for the implementers. |
|
I agree generally with Andi’s opinions but this is a specification and the paragraph is extremely non-specific. Deleting it removes ambiguity without forbidding handling of other values: it leaves it at the discretion of the server rather than making a vague recommendation that clients can’t rely on and servers may implement differently. If nothing else, the “should” should be changed to a “may” to indicate to clients that support for other input values is very much server dependent and may not be accepted at all, and the examples should be removed and replaced with more compelling examples such as using language or transport specific date types. But removing the paragraph is the cheapest fix IMO. |
|
@martinbonnin @benjie I created a short alternative section based on our section. Let me know what you think |
Co-authored-by: Andreas Marek <[email protected]>
| Most Scalars adhere to a semantic symmetry between input and output: every valid | ||
| input value has at least one corresponding output value and vice versa. | ||
|
|
||
| Additionally, it is common to allow different input values, which are | ||
| semantically identical but not technically the same. For example, the ID Scalar | ||
| accepts Int and String literals, while the output value is always String. This | ||
| can improve user experience by allowing flexible inputs. |
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.
| Most Scalars adhere to a semantic symmetry between input and output: every valid | |
| input value has at least one corresponding output value and vice versa. | |
| Additionally, it is common to allow different input values, which are | |
| semantically identical but not technically the same. For example, the ID Scalar | |
| accepts Int and String literals, while the output value is always String. This | |
| can improve user experience by allowing flexible inputs. | |
| For some scalars, input coercion may be more flexible than result coercion. | |
| For example, the ID Scalar accepts both int and strings literals (for both GraphQL | |
| and JSON literals), while the result is always a string. This can improve user experience by | |
| allowing flexible inputs. |
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 @andimarek I stand by my position that flexibility isn't necessarily improving the user experience.
That being said, we also have onError: null and a bunch of other things to move in 2026 so I'm fine letting this one go. Plus this PR didn't get much traction outside our small group so we can revisit if that topic resurfaces later.
@andimarek I've merged your proposal as I like it better that the current text. I've also suggested a shorter alternative above. Feel free to merge it or dismiss it, your call.
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.
Off topic, but you’ve just demonstrated my concern with onError: "NULL" by specifying it as the null literal. There are many servers that don’t distinguish between “present and null” versus “not present”, so it must be string value to be meaningful and backwards compatible.
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.
It's fine. I'm just lazy when writing comments on Christmas day. Implementations will be much better.
Any other value I wouldn't have remembered and I think everyone understands what I meant there.
A server wouldn't but it wasn't the audience of this comment.
|
@andimarek I'm leaving this in your hands. Feel free to:
On Jan 19th, I'll close by default. |
Follow up from #26 (comment)
I find the Robustness principle to be generally harmful for the reasons outlined in this RFC.
It also complexifies the handling of scalars because it breaks the symmetry between output and input wire formats.
For an example, a lot of specifications right now have different examples for input vs. output. That duplicates a lot of information.
GraphQL being generally typesafe and the number of GraphQL servers being limited, I think we can be strict about what we accept.