Skip to content

Commit d4a865a

Browse files
eapachem14tleebyron
authored
[RFC] Custom Scalar Specification URLs (#649)
* First draft of spec changes for the scalar RFC * Add a bit about changing the URI As Benjie noted, it's a bad idea (though not strictly breaking, if the spec has simply moved). Also tidy up the previous paragraph a bit. * Clarify some points raised at working group * switch to a directive * Minor fixes based on feedback * Use "URL" instead of "RFC3986-compliant URI" They're not quite the same thing, but URL is what we actually mean even if it's less formally specified. * Tweak introspection language Not all scalars will have a `specifiedBy` value so "should" was too strong. * Use UUID as a less controversial example Also fix a few more URI->URL references. * Update directive name to @SpecifiedBy * Tweak language * Americanize spelling in spec/Section 3 -- Type System.md Co-Authored-By: Matt Farmer <[email protected]> * Add link to RFC4122 Co-Authored-By: Lee Byron <[email protected]> * Update spec/Section 4 -- Introspection.md Co-Authored-By: Lee Byron <[email protected]> * Minor wording and formatting tweaks * Editorial * Editorial for Scalars section * Editorial to reduce duplication and centralize info * Editorial - grammar * Editorial - simplify introspection change * Editorial - introspection description * Editorial - return note about use of descriptions * Editorial - directive description * Update Section 3 -- Type System.md * address review * additional editorial adjustment Co-authored-by: Matt Farmer <[email protected]> Co-authored-by: Lee Byron <[email protected]> Co-authored-by: Lee Byron <[email protected]>
1 parent 9ec15e3 commit d4a865a

File tree

2 files changed

+71
-15
lines changed

2 files changed

+71
-15
lines changed

spec/Section 3 -- Type System.md

+64-13
Original file line numberDiff line numberDiff line change
@@ -358,19 +358,9 @@ Scalar types represent primitive leaf values in a GraphQL type system. GraphQL
358358
responses take the form of a hierarchical tree; the leaves of this tree are
359359
typically GraphQL Scalar types (but may also be Enum types or {null} values).
360360

361-
GraphQL provides a number of built-in scalars (see below), but type systems can
362-
add additional scalars with semantic meaning. For example, a GraphQL system
363-
could define a scalar called `Time` which, while serialized as a string,
364-
promises to conform to ISO-8601. When querying a field of type `Time`, you can
365-
then rely on the ability to parse the result with an ISO-8601 parser and use a
366-
client-specific primitive for time. Another example of a potentially useful
367-
custom scalar is `Url`, which serializes as a string, but is guaranteed by
368-
the service to be a valid URL.
369-
370-
```graphql example
371-
scalar Time
372-
scalar Url
373-
```
361+
GraphQL provides a number of built-in scalars which are fully defined in the
362+
sections below, however type systems may also add additional custom scalars to
363+
introduce additional semantic meaning.
374364

375365
**Built-in Scalars**
376366

@@ -390,6 +380,43 @@ that type) then it must not be included.
390380
When representing a GraphQL schema using the type system definition language,
391381
all built-in scalars must be omitted for brevity.
392382

383+
**Custom Scalars**
384+
385+
GraphQL services may use custom scalar types in addition to the built-in
386+
scalars. For example, a GraphQL service could define a scalar called `UUID`
387+
which, while serialized as a string, conforms to [RFC 4122](https://tools.ietf.org/html/rfc4122).
388+
When querying a field of type `UUID`, you can then rely on the ability to parse
389+
the result with a RFC 4122 compliant parser. Another example of a potentially
390+
useful custom scalar is `URL`, which serializes as a string, but is guaranteed
391+
by the server to be a valid URL.
392+
393+
When defining a custom scalar, GraphQL services should provide a specification
394+
URL via the `@specifiedBy` directive or the `specifiedBy` introspection field.
395+
This URL must link to a human-readable specification of the data format,
396+
serialization, and coercion rules for the scalar. For example, a GraphQL service
397+
providing a `UUID` scalar may link to RFC 4122, or some custom document defining
398+
a reasonable subset of that RFC. If a scalar `specifiedBy` URL is present,
399+
systems and tools that are aware of it should conform to its described rules.
400+
401+
```graphql example
402+
scalar UUID @specifiedBy(url: "https://tools.ietf.org/html/rfc4122")
403+
scalar URL @specifiedBy(url: "https://tools.ietf.org/html/rfc3986")
404+
```
405+
406+
Custom scalar specifications should provide a single, stable format to avoid
407+
ambiguity. If the linked specification is in flux, the service should link to a
408+
fixed version rather than to a resource which might change.
409+
410+
Custom scalar specification URLs should not be changed once defined. Doing so
411+
would likely disrupt tooling or could introduce breaking changes within the
412+
linked specification's contents.
413+
414+
Built-in scalar types must not provide a `specifiedBy` URL as they are specified
415+
by this document.
416+
417+
Note: Custom scalars should also summarize the specified format and provide
418+
examples in their description.
419+
393420
**Result Coercion and Serialization**
394421

395422
A GraphQL service, when preparing a field of a given scalar type, must uphold the
@@ -1850,6 +1877,10 @@ GraphQL implementations that support the type system definition language must
18501877
provide the `@deprecated` directive if representing deprecated portions of
18511878
the schema.
18521879

1880+
GraphQL implementations that support the type system definition language should
1881+
provide the `@specifiedBy` directive if representing custom scalar
1882+
definitions.
1883+
18531884
**Custom Directives**
18541885

18551886
GraphQL services and client tooling may provide additional directives beyond
@@ -2012,3 +2043,23 @@ type ExampleType {
20122043
oldField: String @deprecated(reason: "Use `newField`.")
20132044
}
20142045
```
2046+
2047+
2048+
### @specifiedBy
2049+
2050+
```graphql
2051+
directive @specifiedBy(url: String!) on SCALAR
2052+
```
2053+
2054+
The `@specifiedBy` directive is used within the type system definition language
2055+
to provide a URL for specifying the behavior of
2056+
[custom scalar types](#sec-Scalars.Custom-Scalars). The URL should point to a
2057+
human-readable specification of the data format, serialization, and
2058+
coercion rules. It must not appear on built-in scalar types.
2059+
2060+
In this example, a custom scalar type for `UUID` is defined with a URL pointing
2061+
to the relevant IETF specification.
2062+
2063+
```graphql example
2064+
scalar UUID @specifiedBy(url: "https://tools.ietf.org/html/rfc4122")
2065+
```

spec/Section 4 -- Introspection.md

+7-2
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ type __Type {
150150

151151
# should be non-null for NON_NULL and LIST only, must be null for the others
152152
ofType: __Type
153+
154+
# should be non-null for custom SCALAR only, must be null for the others
155+
specifiedBy: String
153156
}
154157

155158
type __Field {
@@ -238,13 +241,15 @@ actually valid. These kinds are listed in the `__TypeKind` enumeration.
238241

239242
Represents scalar types such as Int, String, and Boolean. Scalars cannot have fields.
240243

241-
A GraphQL type designer should describe the data format and scalar coercion
242-
rules in the description field of any scalar.
244+
Also represents [Custom scalars](#sec-Scalars.Custom-Scalars) which may provide
245+
`specifiedBy` as a scalar specification URL.
243246

244247
Fields
245248

246249
* `kind` must return `__TypeKind.SCALAR`.
247250
* `name` must return a String.
251+
* `specifiedBy` may return a String (in the form of a URL) for custom scalars,
252+
otherwise must be {null}.
248253
* `description` may return a String or {null}.
249254
* All other fields must return {null}.
250255

0 commit comments

Comments
 (0)