Skip to content

Commit

Permalink
Improve clarity of scalar types (#597)
Browse files Browse the repository at this point in the history
* Improve clarity of scalar types

Attempts a more holistic fix to #535 which unifies language around built-in scalars and serialization, shortening the intro to this section in the process.

* Add clarifying note about Enum leafs in Scalar section
  • Loading branch information
leebyron authored Jan 10, 2020
1 parent 8ada467 commit 39f7a34
Showing 1 changed file with 46 additions and 42 deletions.
88 changes: 46 additions & 42 deletions spec/Section 3 -- Type System.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,18 +327,14 @@ represent additional fields a GraphQL client only accesses locally.
ScalarTypeDefinition : Description? scalar Name Directives[Const]?

Scalar types represent primitive leaf values in a GraphQL type system. GraphQL
responses take the form of a hierarchical tree; the leaves on these trees are
GraphQL scalars.

All GraphQL scalars are representable as strings, though depending on the
response format being used, there may be a more appropriate primitive for the
given scalar type, and server should use those types when appropriate.

GraphQL provides a number of built-in scalars, but type systems can add
additional scalars with semantic meaning. For example, a GraphQL system could
define a scalar called `Time` which, while serialized as a string, promises to
conform to ISO-8601. When querying a field of type `Time`, you can then rely on
the ability to parse the result with an ISO-8601 parser and use a
responses take the form of a hierarchical tree; the leaves of this tree are
typically GraphQL Scalar types (but may also be Enum types or {null} values).

GraphQL provides a number of built-in scalars (see below), but type systems can
add additional scalars with semantic meaning. For example, a GraphQL system
could define a scalar called `Time` which, while serialized as a string,
promises to conform to ISO-8601. When querying a field of type `Time`, you can
then rely on the ability to parse the result with an ISO-8601 parser and use a
client-specific primitive for time. Another example of a potentially useful
custom scalar is `Url`, which serializes as a string, but is guaranteed by
the server to be a valid URL.
Expand All @@ -348,34 +344,48 @@ scalar Time
scalar Url
```

A server may omit any of the built-in scalars from its schema, for example if a
schema does not refer to a floating-point number, then it may omit the
`Float` type. However, if a schema includes a type with the name of one of the
types described here, it must adhere to the behavior described. As an example,
a server must not include a type called `Int` and use it to represent
128-bit numbers, internationalization information, or anything other than what
is defined in this document.
**Built-in Scalars**

GraphQL specifies a basic set of well-defined Scalar types: {Int}, {Float},
{String}, {Boolean}, and {ID}. A GraphQL framework should support all of these
types, and a GraphQL service which provides a type by these names must adhere to
the behavior described for them in this document. As an example, a service must
not include a type called {Int} and use it to represent 64-bit numbers,
internationalization information, or anything other than what is defined in
this document.

When returning the set of types from the `__Schema` introspection type, all
referenced built-in scalars must be included. If a built-in scalar type is not
referenced anywhere in a schema (there is no field, argument, or input field of
that type) then it must not be included.

When representing a GraphQL schema using the type system definition language,
the built-in scalar types should be omitted for brevity.
all built-in scalars must be omitted for brevity.

**Result Coercion**
**Result Coercion and Serialization**

A GraphQL server, when preparing a field of a given scalar type, must uphold the
contract the scalar type describes, either by coercing the value or producing a
field error if a value cannot be coerced or if coercion may result in data loss.

A GraphQL service may decide to allow coercing different internal types to the
expected return type. For example when coercing a field of type `Int` a boolean
`true` value may produce `1` or a string value `"123"` may be parsed as base-10
`123`. However if internal type coercion cannot be reasonably performed without
expected return type. For example when coercing a field of type {Int} a boolean
{true} value may produce {1} or a string value {"123"} may be parsed as base-10
{123}. However if internal type coercion cannot be reasonably performed without
losing information, then it must raise a field error.

Since this coercion behavior is not observable to clients of the GraphQL server,
the precise rules of coercion are left to the implementation. The only
requirement is that the server must yield values which adhere to the expected
Scalar type.

GraphQL scalars are serialized according to the serialization format being used.
There may be a most appropriate serialized primitive for each given scalar type,
and the server should produce each primitive where appropriate.

See [Serialization Format](#sec-Serialization-Format) for more detailed
information on the serialization of scalars in common JSON and other formats.

**Input Coercion**

If a GraphQL server expects a scalar type as input to an argument, coercion
Expand All @@ -394,12 +404,6 @@ input value.
For all types below, with the exception of Non-Null, if the explicit value
{null} is provided, then the result of input coercion is {null}.

**Built-in Scalars**

GraphQL provides a basic set of well-defined Scalar types. A GraphQL server
should support all of these types, and a GraphQL server which provide a type by
these names must adhere to the behavior described below.


### Int

Expand All @@ -409,7 +413,7 @@ that type to represent this scalar.

**Result Coercion**

Fields returning the type `Int` expect to encounter 32-bit integer
Fields returning the type {Int} expect to encounter 32-bit integer
internal values.

GraphQL servers may coerce non-integer internal values to integers when
Expand Down Expand Up @@ -444,10 +448,10 @@ should use that type to represent this scalar.

**Result Coercion**

Fields returning the type `Float` expect to encounter double-precision
Fields returning the type {Float} expect to encounter double-precision
floating-point internal values.

GraphQL servers may coerce non-floating-point internal values to `Float` when
GraphQL servers may coerce non-floating-point internal values to {Float} when
reasonable without losing information, otherwise they must raise a field error.
Examples of this may include returning `1.0` for the integer number `1`, or
`123.0` for the string `"123"`.
Expand All @@ -471,9 +475,9 @@ and that representation must be used here.

**Result Coercion**

Fields returning the type `String` expect to encounter UTF-8 string internal values.
Fields returning the type {String} expect to encounter UTF-8 string internal values.

GraphQL servers may coerce non-string raw values to `String` when reasonable
GraphQL servers may coerce non-string raw values to {String} when reasonable
without losing information, otherwise they must raise a field error. Examples of
this may include returning the string `"true"` for a boolean true value, or the
string `"1"` for the integer `1`.
Expand All @@ -493,9 +497,9 @@ representation of the integers `1` and `0`.

**Result Coercion**

Fields returning the type `Boolean` expect to encounter boolean internal values.
Fields returning the type {Boolean} expect to encounter boolean internal values.

GraphQL servers may coerce non-boolean raw values to `Boolean` when reasonable
GraphQL servers may coerce non-boolean raw values to {Boolean} when reasonable
without losing information, otherwise they must raise a field error. Examples of
this may include returning `true` for non-zero numbers.

Expand All @@ -509,8 +513,8 @@ other input values must raise a query error indicating an incorrect type.

The ID scalar type represents a unique identifier, often used to refetch an
object or as the key for a cache. The ID type is serialized in the same way as
a `String`; however, it is not intended to be human-readable. While it is
often numeric, it should always serialize as a `String`.
a {String}; however, it is not intended to be human-readable. While it is
often numeric, it should always serialize as a {String}.

**Result Coercion**

Expand Down Expand Up @@ -583,8 +587,8 @@ type Person {
}
```

Where `name` is a field that will yield a `String` value, and `age` is a field
that will yield an `Int` value, and `picture` is a field that will yield a
Where `name` is a field that will yield a {String} value, and `age` is a field
that will yield an {Int} value, and `picture` is a field that will yield a
`Url` value.

A query of an object value must select at least one field. This selection of
Expand Down Expand Up @@ -1250,7 +1254,7 @@ EnumValuesDefinition : { EnumValueDefinition+ }

EnumValueDefinition : Description? EnumValue Directives[Const]?

GraphQL Enum types, like scalar types, also represent leaf values in a GraphQL
GraphQL Enum types, like Scalar types, also represent leaf values in a GraphQL
type system. However Enum types describe the set of possible values.

Enums are not references for a numeric value, but are unique values in their own
Expand Down

0 comments on commit 39f7a34

Please sign in to comment.