Skip to content

Commit 78538bc

Browse files
committed
[FIX] Throw field errors when failing to coerce Int/Float.
As illustrated by #391, when a value is provided for a field of type Int which cannot be represented by Int (e.g. a 64bit value is provided to the 32bit Int type), then the spec claims a field-error should be raised however currently `null` is returned directly instead. Spec: https://facebook.github.io/graphql/#sec-Int This updates to throw meaningful error messages when invalid Int and Float values cannot be coerced without losing information.
1 parent a73c8e2 commit 78538bc

File tree

3 files changed

+49
-17
lines changed

3 files changed

+49
-17
lines changed

src/type/__tests__/serialization-test.js

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ describe('Type System: Scalar coercion', () => {
2323
expect(
2424
GraphQLInt.serialize(1)
2525
).to.equal(1);
26+
expect(
27+
GraphQLInt.serialize('123')
28+
).to.equal(123);
2629
expect(
2730
GraphQLInt.serialize(0)
2831
).to.equal(0);
@@ -43,25 +46,35 @@ describe('Type System: Scalar coercion', () => {
4346
).to.equal(100000);
4447
// Maybe a safe JavaScript int, but bigger than 2^32, so not
4548
// representable as a GraphQL Int
46-
expect(
49+
expect(() =>
4750
GraphQLInt.serialize(9876504321)
48-
).to.equal(null);
49-
expect(
51+
).to.throw(
52+
'Int cannot represent non 32-bit signed integer value: 9876504321'
53+
);
54+
expect(() =>
5055
GraphQLInt.serialize(-9876504321)
51-
).to.equal(null);
56+
).to.throw(
57+
'Int cannot represent non 32-bit signed integer value: -9876504321'
58+
);
5259
// Too big to represent as an Int in JavaScript or GraphQL
53-
expect(
60+
expect(() =>
5461
GraphQLInt.serialize(1e100)
55-
).to.equal(null);
56-
expect(
62+
).to.throw(
63+
'Int cannot represent non 32-bit signed integer value: 1e+100'
64+
);
65+
expect(() =>
5766
GraphQLInt.serialize(-1e100)
58-
).to.equal(null);
67+
).to.throw(
68+
'Int cannot represent non 32-bit signed integer value: -1e+100'
69+
);
5970
expect(
6071
GraphQLInt.serialize('-1.1')
6172
).to.equal(-1);
62-
expect(
73+
expect(() =>
6374
GraphQLInt.serialize('one')
64-
).to.equal(null);
75+
).to.throw(
76+
'Int cannot represent non 32-bit signed integer value: one'
77+
);
6578
expect(
6679
GraphQLInt.serialize(false)
6780
).to.equal(0);
@@ -77,6 +90,9 @@ describe('Type System: Scalar coercion', () => {
7790
expect(
7891
GraphQLFloat.serialize(0)
7992
).to.equal(0.0);
93+
expect(
94+
GraphQLFloat.serialize('123.5')
95+
).to.equal(123.5);
8096
expect(
8197
GraphQLFloat.serialize(-1)
8298
).to.equal(-1.0);
@@ -92,15 +108,24 @@ describe('Type System: Scalar coercion', () => {
92108
expect(
93109
GraphQLFloat.serialize('-1.1')
94110
).to.equal(-1.1);
95-
expect(
96-
GraphQLFloat.serialize('one')
97-
).to.equal(null);
98111
expect(
99112
GraphQLFloat.serialize(false)
100113
).to.equal(0.0);
101114
expect(
102115
GraphQLFloat.serialize(true)
103116
).to.equal(1.0);
117+
118+
expect(() =>
119+
GraphQLFloat.serialize(NaN)
120+
).to.throw(
121+
'Float cannot represent non numeric value: NaN'
122+
);
123+
124+
expect(() =>
125+
GraphQLFloat.serialize('one')
126+
).to.throw(
127+
'Float cannot represent non numeric value: one'
128+
);
104129
});
105130

106131
it('serializes output strings', () => {

src/type/scalars.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ function coerceInt(value: mixed): ?number {
2424
if (num === num && num <= MAX_INT && num >= MIN_INT) {
2525
return (num < 0 ? Math.ceil : Math.floor)(num);
2626
}
27-
return null;
27+
throw new TypeError(
28+
'Int cannot represent non 32-bit signed integer value: ' + value
29+
);
2830
}
2931

3032
export const GraphQLInt = new GraphQLScalarType({
@@ -47,7 +49,12 @@ export const GraphQLInt = new GraphQLScalarType({
4749

4850
function coerceFloat(value: mixed): ?number {
4951
const num = Number(value);
50-
return num === num ? num : null;
52+
if (num === num) {
53+
return num;
54+
}
55+
throw new TypeError(
56+
'Float cannot represent non numeric value: ' + value
57+
);
5158
}
5259

5360
export const GraphQLFloat = new GraphQLScalarType({

src/utilities/__tests__/astFromValue-test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ describe('astFromValue', () => {
6060
);
6161

6262
// Note: outside the bounds of 32bit signed int.
63-
expect(astFromValue(1e40, GraphQLInt)).to.deep.equal(
64-
null
63+
expect(() => astFromValue(1e40, GraphQLInt)).to.throw(
64+
'Int cannot represent non 32-bit signed integer value: 1e+40'
6565
);
6666
});
6767

0 commit comments

Comments
 (0)