Skip to content

Commit

Permalink
[RFC] Custom Scalar Specification URLs (#649)
Browse files Browse the repository at this point in the history
* 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 <work@mattfarmer.net>

* Add link to RFC4122

Co-Authored-By: Lee Byron <lee@leebyron.com>

* Update spec/Section 4 -- Introspection.md

Co-Authored-By: Lee Byron <lee@leebyron.com>

* 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 <work@mattfarmer.net>
Co-authored-by: Lee Byron <lee@leebyron.com>
Co-authored-by: Lee Byron <lee.byron@robinhood.com>
  • Loading branch information
4 people committed Apr 9, 2021
1 parent 9ec15e3 commit d4a865a
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 15 deletions.
77 changes: 64 additions & 13 deletions spec/Section 3 -- Type System.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,19 +358,9 @@ Scalar types represent primitive leaf values in a GraphQL type system. GraphQL
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 service to be a valid URL.

```graphql example
scalar Time
scalar Url
```
GraphQL provides a number of built-in scalars which are fully defined in the
sections below, however type systems may also add additional custom scalars to
introduce additional semantic meaning.

**Built-in Scalars**

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

**Custom Scalars**

GraphQL services may use custom scalar types in addition to the built-in
scalars. For example, a GraphQL service could define a scalar called `UUID`
which, while serialized as a string, conforms to [RFC 4122](https://tools.ietf.org/html/rfc4122).
When querying a field of type `UUID`, you can then rely on the ability to parse
the result with a RFC 4122 compliant parser. 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.

When defining a custom scalar, GraphQL services should provide a specification
URL via the `@specifiedBy` directive or the `specifiedBy` introspection field.
This URL must link to a human-readable specification of the data format,
serialization, and coercion rules for the scalar. For example, a GraphQL service
providing a `UUID` scalar may link to RFC 4122, or some custom document defining
a reasonable subset of that RFC. If a scalar `specifiedBy` URL is present,
systems and tools that are aware of it should conform to its described rules.

```graphql example
scalar UUID @specifiedBy(url: "https://tools.ietf.org/html/rfc4122")
scalar URL @specifiedBy(url: "https://tools.ietf.org/html/rfc3986")
```

Custom scalar specifications should provide a single, stable format to avoid
ambiguity. If the linked specification is in flux, the service should link to a
fixed version rather than to a resource which might change.

Custom scalar specification URLs should not be changed once defined. Doing so
would likely disrupt tooling or could introduce breaking changes within the
linked specification's contents.

Built-in scalar types must not provide a `specifiedBy` URL as they are specified
by this document.

Note: Custom scalars should also summarize the specified format and provide
examples in their description.

**Result Coercion and Serialization**

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

GraphQL implementations that support the type system definition language should
provide the `@specifiedBy` directive if representing custom scalar
definitions.

**Custom Directives**

GraphQL services and client tooling may provide additional directives beyond
Expand Down Expand Up @@ -2012,3 +2043,23 @@ type ExampleType {
oldField: String @deprecated(reason: "Use `newField`.")
}
```


### @specifiedBy

```graphql
directive @specifiedBy(url: String!) on SCALAR
```

The `@specifiedBy` directive is used within the type system definition language
to provide a URL for specifying the behavior of
[custom scalar types](#sec-Scalars.Custom-Scalars). The URL should point to a
human-readable specification of the data format, serialization, and
coercion rules. It must not appear on built-in scalar types.

In this example, a custom scalar type for `UUID` is defined with a URL pointing
to the relevant IETF specification.

```graphql example
scalar UUID @specifiedBy(url: "https://tools.ietf.org/html/rfc4122")
```
9 changes: 7 additions & 2 deletions spec/Section 4 -- Introspection.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ type __Type {

# should be non-null for NON_NULL and LIST only, must be null for the others
ofType: __Type

# should be non-null for custom SCALAR only, must be null for the others
specifiedBy: String
}

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

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

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

Fields

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

Expand Down

0 comments on commit d4a865a

Please sign in to comment.