Skip to content

Commit

Permalink
[FIX] Throw field errors when failing to coerce Int/Float.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
leebyron committed Jul 20, 2016
1 parent a73c8e2 commit 78538bc
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 17 deletions.
51 changes: 38 additions & 13 deletions src/type/__tests__/serialization-test.js
Expand Up @@ -23,6 +23,9 @@ describe('Type System: Scalar coercion', () => {
expect(
GraphQLInt.serialize(1)
).to.equal(1);
expect(
GraphQLInt.serialize('123')
).to.equal(123);
expect(
GraphQLInt.serialize(0)
).to.equal(0);
Expand All @@ -43,25 +46,35 @@ describe('Type System: Scalar coercion', () => {
).to.equal(100000);
// Maybe a safe JavaScript int, but bigger than 2^32, so not
// representable as a GraphQL Int
expect(
expect(() =>
GraphQLInt.serialize(9876504321)
).to.equal(null);
expect(
).to.throw(
'Int cannot represent non 32-bit signed integer value: 9876504321'
);
expect(() =>
GraphQLInt.serialize(-9876504321)
).to.equal(null);
).to.throw(
'Int cannot represent non 32-bit signed integer value: -9876504321'
);
// Too big to represent as an Int in JavaScript or GraphQL
expect(
expect(() =>
GraphQLInt.serialize(1e100)
).to.equal(null);
expect(
).to.throw(
'Int cannot represent non 32-bit signed integer value: 1e+100'
);
expect(() =>
GraphQLInt.serialize(-1e100)
).to.equal(null);
).to.throw(
'Int cannot represent non 32-bit signed integer value: -1e+100'
);
expect(
GraphQLInt.serialize('-1.1')
).to.equal(-1);
expect(
expect(() =>
GraphQLInt.serialize('one')
).to.equal(null);
).to.throw(
'Int cannot represent non 32-bit signed integer value: one'
);
expect(
GraphQLInt.serialize(false)
).to.equal(0);
Expand All @@ -77,6 +90,9 @@ describe('Type System: Scalar coercion', () => {
expect(
GraphQLFloat.serialize(0)
).to.equal(0.0);
expect(
GraphQLFloat.serialize('123.5')
).to.equal(123.5);
expect(
GraphQLFloat.serialize(-1)
).to.equal(-1.0);
Expand All @@ -92,15 +108,24 @@ describe('Type System: Scalar coercion', () => {
expect(
GraphQLFloat.serialize('-1.1')
).to.equal(-1.1);
expect(
GraphQLFloat.serialize('one')
).to.equal(null);
expect(
GraphQLFloat.serialize(false)
).to.equal(0.0);
expect(
GraphQLFloat.serialize(true)
).to.equal(1.0);

expect(() =>
GraphQLFloat.serialize(NaN)
).to.throw(
'Float cannot represent non numeric value: NaN'
);

expect(() =>
GraphQLFloat.serialize('one')
).to.throw(
'Float cannot represent non numeric value: one'
);
});

it('serializes output strings', () => {
Expand Down
11 changes: 9 additions & 2 deletions src/type/scalars.js
Expand Up @@ -24,7 +24,9 @@ function coerceInt(value: mixed): ?number {
if (num === num && num <= MAX_INT && num >= MIN_INT) {
return (num < 0 ? Math.ceil : Math.floor)(num);
}
return null;
throw new TypeError(
'Int cannot represent non 32-bit signed integer value: ' + value
);
}

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

function coerceFloat(value: mixed): ?number {
const num = Number(value);
return num === num ? num : null;
if (num === num) {
return num;
}
throw new TypeError(
'Float cannot represent non numeric value: ' + value
);
}

export const GraphQLFloat = new GraphQLScalarType({
Expand Down
4 changes: 2 additions & 2 deletions src/utilities/__tests__/astFromValue-test.js
Expand Up @@ -60,8 +60,8 @@ describe('astFromValue', () => {
);

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

Expand Down

0 comments on commit 78538bc

Please sign in to comment.