Skip to content

Commit

Permalink
Update the relay specific specifications to consider them generic bes…
Browse files Browse the repository at this point in the history
…t practices and not purely a relay spec (#2603)

Summary:
Better late than never, roughly a year ago in the GraphQL Working Group 3 we took it on Artsy to start moving the Relay specs to be considered "GraphQL Best Practices" ([link](https://github.com/graphql/graphql-wg/blob/master/notes/2018-02-01.md#discuss-moving-connectionglobal-id-specs-from-relay-into-best-practices-repo))

This starts that, beginning with first minimizing the use of Relay as being the sole client that conforms to the connection and object identifier spec.

Main notes:

- When referring to relay on the client I switched "Relay" to "Spec-compliant client" or "client"
- When referring to relay's compatibility on the server side, I oriented it to just be "spec-compliant"
- I mostly left the Mutation input spec alone, now that it's only for Relay classic and is close to being removed completely from Relay #2349
- This is step one, once this is merged then I'd like to move both object identification and connection to be on the graphql repos instead of relay and I can handle link updating etc

Happy to change wording etc

/cc leebyron in case you don't watch this repo too closely.
Pull Request resolved: #2603

Reviewed By: josephsavona

Differential Revision: D19071019

Pulled By: jstejada

fbshipit-source-id: cf5a7dfb93cfd565d4f178a51cdff7cd0caec1a0
  • Loading branch information
orta authored and facebook-github-bot committed Dec 19, 2019
1 parent b4e7e43 commit 0cd681e
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 53 deletions.
4 changes: 2 additions & 2 deletions docs/GraphQL-ServerSpecification.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ The `Node` interface and `node` field assume globally unique IDs for this refetc

The IDs we got back were base64 strings. IDs are designed to be opaque (the only thing that should be passed to the `id` argument on `node` is the unaltered result of querying `id` on some object in the system), and base64ing a string is a useful convention in GraphQL to remind viewers that the string is an opaque identifier.

Complete details on how the server should behave are available in the [GraphQL Object Identification](/graphql/objectidentification.htm) spec.
Complete details on how the server should behave are available in the [GraphQL Object Identification](https://graphql.org/learn/global-object-identification/) best practices guide in the GraphQL site.

## Connections

Expand Down Expand Up @@ -508,6 +508,6 @@ and we'll get this result:

## Further Reading

This concludes the overview of the GraphQL Server Specifications. For the detailed requirements of a Relay-compliant GraphQL server, a more formal description of the [Relay cursor connection](/graphql/connections.htm) model and the [Relay global object identification](/graphql/objectidentification.htm) model are all available.
This concludes the overview of the GraphQL Server Specifications. For the detailed requirements of a Relay-compliant GraphQL server, a more formal description of the [Relay cursor connection](/graphql/connections.htm) model, the [GraphQL global object identification](https://graphql.org/learn/global-object-identification/) model are all available.

To see code implementing the specification, the [GraphQL.js Relay library](https://github.com/graphql/graphql-relay-js) provides helper functions for creating nodes, connections, and mutations; that repository's [`__tests__`](https://github.com/graphql/graphql-relay-js/tree/master/src/__tests__) folder contains an implementation of the above example as integration tests for the repository.
6 changes: 6 additions & 0 deletions website/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,12 @@
},
"version-v7.0.0/version-v7.0.0-network-layer": {
"title": "Network Layer"
},
"version-v7.1.0/version-v7.1.0-quick-start-guide": {
"title": "Quick Start Guide"
},
"version-v7.1.0/version-v7.1.0-local-state-management": {
"title": "Local State Management"
}
},
"links": {
Expand Down
3 changes: 2 additions & 1 deletion website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"publish-gh-pages": "docusaurus-publish",
"write-translations": "docusaurus-write-translations",
"crowdin-upload": "crowdin-cli --config ../crowdin.yaml upload sources --auto-update -b master",
"crowdin-download": "crowdin-cli --config ../crowdin.yaml download -b master"
"crowdin-download": "crowdin-cli --config ../crowdin.yaml download -b master",
"update-specs":"spec-md spec/Connections.md > static/graphql/connections.htm; spec-md spec/Mutations.md > static/graphql/mutations.htm; spec-md spec/ObjectIdentification.md > static/graphql/objectidentification.htm"
},
"dependencies": {
"docusaurus": "1.14.0",
Expand Down
32 changes: 19 additions & 13 deletions website/spec/Connections.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
Relay Cursor Connections Specification
GraphQL Cursor Connections Specification
--------------------------------------

Relay's support for pagination relies on the GraphQL server exposing
connections in a standardized way. In the query, the connection model
provides a standard mechanism for slicing and paginating the result set.
This specification aims to provide an option for GraphQL clients to consistently
handle [pagination best practices](https://graphql.org/learn/pagination/) with
support for related metadata via a GraphQL server. This spec proposes calling
this pattern "Connections" and exposing them in a standardized way.

In the query, the connection model provides a standard mechanism for slicing
and paginating the result set.

In the response, the connection model provides a standard way of providing
cursors, and a way of telling the client when more results are available.

Expand Down Expand Up @@ -47,16 +52,16 @@ This section of the spec describes the formal requirements around connections.

# Reserved Types

A GraphQL Relay server must reserve certain types and type names
to support the pagination model used by Relay. In particular, this spec creates
A GraphQL server which conforms to this spec must reserve certain types and type names
to support the pagination model of connections. In particular, this spec creates
guidelines for the following types:

- Any object whose name ends in "Connection".
- An object named `PageInfo`.

# Connection Types

Any type whose name ends in "Connection" is considered by Relay
Any type whose name ends in "Connection" is considered by this spec
to be a *Connection Type*. Connection types must be an "Object"
as defined in the "Type System" section of the GraphQL Specification.

Expand Down Expand Up @@ -143,7 +148,7 @@ returns
# Edge Types

A type that is returned in list form by a connection type's `edges` field
is considered by Relay to be an *Edge Type*. Edge types must be an "Object"
is considered by this spec to be an *Edge Type*. Edge types must be an "Object"
as defined in the "Type System" section of the GraphQL Specification.

## Fields
Expand All @@ -159,9 +164,9 @@ a Scalar, Enum, Object, Interface, Union, or a Non-Null wrapper around one of
those types. Notably, this field *cannot* return a list.

NOTE The naming echoes that of the "Node" interface and "node" root
field as described in a later section of this spec. Relay can perform
certain optimizations if this field returns an object that implements
`Node`, however, this is not a strict requirement for use of Relay.
field as described in a later section of this spec. Spec-compliant clients
can perform certain optimizations if this field returns an object that implements
`Node`, however, this is not a strict requirement for conforming.

### Cursor

Expand All @@ -173,7 +178,7 @@ Non-Null wrapper around a custom scalar that serializes as a String.
Whatever type this field returns will be referred to as the *cursor type*
in the rest of this spec.

The result of this field is considered opaque by Relay, but will be passed
The result of this field should be considered opaque by the client, but will be passed
back to the server as described in the "Arguments" section below.

## Introspection
Expand Down Expand Up @@ -368,7 +373,8 @@ becomes unclear. This is among the reasons that pagination with both `first` and
`startCursor` and `endCursor` must be the cursors corresponding to the first and
last nodes in `edges`, respectively.

NOTE Relay Legacy did not define `startCursor` and `endCursor`, and relied on
NOTE As this spec was created with Relay Classic in mind, it's worth noting that
Relay Legacy did not define `startCursor` and `endCursor`, and relied on
selecting the `cursor` of each edge; Relay Modern began selecting
`startCursor` and `endCursor` instead to save bandwidth (since it doesn't use any
cursors in between).
Expand Down
27 changes: 14 additions & 13 deletions website/spec/ObjectIdentification.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
Relay Global Object Identification Specification
GraphQL Global Object Identification Specification
------------------------------------------------

Relay's support for object identification relies on the GraphQL server exposing
object identifiers in a standardized way. In the query, the schema should
provide a standard mechanism for asking for an object by ID. In the response,
the schema provides a standard way of providing these IDs.
To provide options for GraphQL clients to elegantly handle for caching and data
refetching GraphQL servers need to expose object identifiers in a standardized
way. In the query, the schema should provide a standard mechanism for asking
for an object by ID. In the response, the schema provides a standard way of
providing these IDs.

We refer to objects with identifiers as "nodes".

Expand All @@ -28,9 +29,9 @@ refetching.

# Reserved Types

A GraphQL Relay server must reserve certain types and type names
to support the object identification model used by Relay. In particular, this
spec creates guidelines for the following types:
A GraphQL server compatible with this spec must reserve certain types and type names
to support the consistent object identification model. In particular, this spec creates
guidelines for the following types:

- An interface named `Node`.
- The `node` field on the root query type.
Expand Down Expand Up @@ -294,21 +295,21 @@ might return:
}
```

For Relay to be able to link the usernames to the responses, it needs to
For clients to be able to link the usernames to the responses, it needs to
know that the array in the response will be the same size as the array
passed as an argument, and that the order in the response will match the
order in the argument. We call these *plural identifying root fields*, and
their requirements are described below.

## Fields

A Relay-compliant server may expose root fields that accept a list of input
arguments, and returns a list of responses. For Relay to use these fields,
A server compliant with this spec may expose root fields that accept a list of input
arguments, and returns a list of responses. For spec-compliant clients to use these fields,
these fields must be *plural identifying root fields*, and obey the following
requirements.

NOTE Relay-compliant servers may expose root fields that are not *plural
identifying root fields*; the Relay client will just be unable to use those
NOTE Spec-compliant servers may expose root fields that are not *plural
identifying root fields*; the spec-compliant client will just be unable to use those
fields as root fields in its queries.

*Plural identifying root fields* must have a single argument. The type of that
Expand Down
30 changes: 16 additions & 14 deletions website/static/graphql/connections.htm
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<!-- Built with spec-md https://spec-md.com -->
<html>
<head><meta charset="utf-8">
<title>Relay Cursor Connections Specification</title>
<title>GraphQL Cursor Connections Specification</title>
<style>body {
color: #333333;
font: 13pt/18pt Cambria, "Palatino Linotype", Palatino, "Liberation Serif", serif;
Expand Down Expand Up @@ -870,9 +870,11 @@
</head>
<body><article>
<header>
<h1>Relay Cursor Connections Specification</h1>
<h1>GraphQL Cursor Connections Specification</h1>
<section id="intro">
<p>Relay&rsquo;s support for pagination relies on the GraphQL server exposing connections in a standardized way. In the query, the connection model provides a standard mechanism for slicing and paginating the result set. In the response, the connection model provides a standard way of providing cursors, and a way of telling the client when more results are available.</p>
<p>This specification aims to provide an option for GraphQL clients to consistently handle <a href="https://graphql.org/learn/pagination/">pagination best practices</a> with support for related metadata via a GraphQL server. This spec proposes calling this pattern &ldquo;Connections&rdquo; and exposing them in a standardized way. </p>
<p>In the query, the connection model provides a standard mechanism for slicing and paginating the result set.</p>
<p>In the response, the connection model provides a standard way of providing cursors, and a way of telling the client when more results are available.</p>
<p>An example of all four of those is the following query:</p>
<pre><code><span class="token punctuation">{</span>
user <span class="token punctuation">{</span>
Expand Down Expand Up @@ -954,15 +956,15 @@ <h1>Relay Cursor Connections Specification</h1>
</header>
<section id="sec-Reserved-Types" secid="1">
<h2><span class="spec-secid" title="link to this section"><a href="#sec-Reserved-Types">1</a></span>Reserved Types</h2>
<p>A GraphQL Relay server must reserve certain types and type names to support the pagination model used by Relay. In particular, this spec creates guidelines for the following types:</p>
<p>A GraphQL server which conforms to this spec must reserve certain types and type names to support the pagination model of connections. In particular, this spec creates guidelines for the following types:</p>
<ul>
<li>Any object whose name ends in &ldquo;Connection&rdquo;.</li>
<li>An object named <code>PageInfo</code>.</li>
</ul>
</section>
<section id="sec-Connection-Types" secid="2">
<h2><span class="spec-secid" title="link to this section"><a href="#sec-Connection-Types">2</a></span>Connection Types</h2>
<p>Any type whose name ends in &ldquo;Connection&rdquo; is considered by Relay to be a <em>Connection Type</em>. Connection types must be an &ldquo;Object&rdquo; as defined in the &ldquo;Type System&rdquo; section of the GraphQL Specification.</p>
<p>Any type whose name ends in &ldquo;Connection&rdquo; is considered by this spec to be a <em>Connection Type</em>. Connection types must be an &ldquo;Object&rdquo; as defined in the &ldquo;Type System&rdquo; section of the GraphQL Specification.</p>
<section id="sec-Connection-Types.Fields" secid="2.1">
<h3><span class="spec-secid" title="link to this section"><a href="#sec-Connection-Types.Fields">2.1</a></span>Fields</h3>
<p>Connection types must have fields named <code>edges</code> and <code>pageInfo</code>. They may have additional fields related to the connection, as the schema designer sees fit.</p>
Expand Down Expand Up @@ -1031,22 +1033,22 @@ <h3><span class="spec-secid" title="link to this section"><a href="#sec-Connecti
</section>
<section id="sec-Edge-Types" secid="3">
<h2><span class="spec-secid" title="link to this section"><a href="#sec-Edge-Types">3</a></span>Edge Types</h2>
<p>A type that is returned in list form by a connection type&rsquo;s <code>edges</code> field is considered by Relay to be an <em>Edge Type</em>. Edge types must be an &ldquo;Object&rdquo; as defined in the &ldquo;Type System&rdquo; section of the GraphQL Specification.</p>
<p>A type that is returned in list form by a connection type&rsquo;s <code>edges</code> field is considered by this spec to be an <em>Edge Type</em>. Edge types must be an &ldquo;Object&rdquo; as defined in the &ldquo;Type System&rdquo; section of the GraphQL Specification.</p>
<section id="sec-Edge-Types.Fields" secid="3.1">
<h3><span class="spec-secid" title="link to this section"><a href="#sec-Edge-Types.Fields">3.1</a></span>Fields</h3>
<p>Edge types must have fields named <code>node</code> and <code>cursor</code>. They may have additional fields related to the edge, as the schema designer sees fit.</p>
<section id="sec-Node" secid="3.1.1">
<h4><span class="spec-secid" title="link to this section"><a href="#sec-Node">3.1.1</a></span>Node</h4>
<p>An &ldquo;Edge Type&rdquo; must contain a field called <code>node</code>. This field must return either a Scalar, Enum, Object, Interface, Union, or a Non&#8208;Null wrapper around one of those types. Notably, this field <em>cannot</em> return a list.</p>
<div id="note-f38dd" class="spec-note">
<a href="#note-f38dd">Note</a>
The naming echoes that of the &ldquo;Node&rdquo; interface and &ldquo;node&rdquo; root field as described in a later section of this spec. Relay can perform certain optimizations if this field returns an object that implements <code>Node</code>, however, this is not a strict requirement for use of Relay.</div>
<div id="note-c0d4d" class="spec-note">
<a href="#note-c0d4d">Note</a>
The naming echoes that of the &ldquo;Node&rdquo; interface and &ldquo;node&rdquo; root field as described in a later section of this spec. Spec&#8208;compliant clients can perform certain optimizations if this field returns an object that implements <code>Node</code>, however, this is not a strict requirement for conforming.</div>
</section>
<section id="sec-Cursor" secid="3.1.2">
<h4><span class="spec-secid" title="link to this section"><a href="#sec-Cursor">3.1.2</a></span>Cursor</h4>
<p>An &ldquo;Edge Type&rdquo; must contain a field called <code>cursor</code>. This field must return a type that serializes as a String; this may be a String, a Non&#8208;Null wrapper around a String, a custom scalar that serializes as a String, or a Non&#8208;Null wrapper around a custom scalar that serializes as a String.</p>
<p>Whatever type this field returns will be referred to as the <em>cursor type</em> in the rest of this spec.</p>
<p>The result of this field is considered opaque by Relay, but will be passed back to the server as described in the &ldquo;Arguments&rdquo; section below.</p>
<p>The result of this field should be considered opaque by the client, but will be passed back to the server as described in the &ldquo;Arguments&rdquo; section below.</p>
</section>
</section>
<section id="sec-Edge-Types.Introspection" secid="3.2">
Expand Down Expand Up @@ -1231,9 +1233,9 @@ <h3><span class="spec-secid" title="link to this section"><a href="#sec-undefine
<a href="#note-95f8a">Note</a>
When both <code>first</code> and <code>last</code> are included, both of the fields should be set according to the above algorithms, but their meaning as it relates to pagination becomes unclear. This is among the reasons that pagination with both <code>first</code> and <code>last</code> is discouraged.</div>
<p><code>startCursor</code> and <code>endCursor</code> must be the cursors corresponding to the first and last nodes in <code>edges</code>, respectively.</p>
<div id="note-4e735" class="spec-note">
<a href="#note-4e735">Note</a>
Relay Legacy did not define <code>startCursor</code> and <code>endCursor</code>, and relied on selecting the <code>cursor</code> of each edge; Relay Modern began selecting <code>startCursor</code> and <code>endCursor</code> instead to save bandwidth (since it doesn&rsquo;t use any cursors in between).</div>
<div id="note-4ca64" class="spec-note">
<a href="#note-4ca64">Note</a>
As this spec was created with Relay Classic in mind, it&rsquo;s worth noting that Relay Legacy did not define <code>startCursor</code> and <code>endCursor</code>, and relied on selecting the <code>cursor</code> of each edge; Relay Modern began selecting <code>startCursor</code> and <code>endCursor</code> instead to save bandwidth (since it doesn&rsquo;t use any cursors in between).</div>
</section>
<section id="sec-undefined.PageInfo.Introspection" secid="5.2">
<h3><span class="spec-secid" title="link to this section"><a href="#sec-undefined.PageInfo.Introspection">5.2</a></span>Introspection</h3>
Expand Down Expand Up @@ -1317,7 +1319,7 @@ <h3><span class="spec-secid" title="link to this section"><a href="#sec-undefine
<input hidden class="spec-sidebar-toggle" type="checkbox" id="spec-sidebar-toggle" aria-hidden /><label for="spec-sidebar-toggle" aria-hidden>&#x2630;</label>
<div class="spec-sidebar" aria-hidden>
<div class="spec-toc">
<div class="title"><a href="#">Relay Cursor Connections Specification</a></div>
<div class="title"><a href="#">GraphQL Cursor Connections Specification</a></div>
<ol><li id="_sidebar_1"><a href="#sec-Reserved-Types"><span class="spec-secid">1</span>Reserved Types</a></li>
<li id="_sidebar_2"><a href="#sec-Connection-Types"><span class="spec-secid">2</span>Connection Types</a>
<input hidden class="toggle" type="checkbox" id="_sidebar_toggle_2" /><label for="_sidebar_toggle_2"></label>
Expand Down
Loading

0 comments on commit 0cd681e

Please sign in to comment.