Skip to content

Commit aaa0928

Browse files
committed
Add Schema Coordinates RFC
1 parent c976d31 commit aaa0928

File tree

1 file changed

+310
-0
lines changed

1 file changed

+310
-0
lines changed

rfcs/SchemaCoordinates.md

Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
# RFC: Schema Coordinates
2+
3+
**Proposed by:** [Mark Larah](https://twitter.com/mark_larah) - Yelp
4+
5+
This RFC proposes formalizing "Schema Coordinates" - a human readable syntax to
6+
uniquely identify a type, field, or field argument defined in a GraphQL Schema.
7+
8+
This should be listed as a non-normative note in the GraphQL specification to
9+
serve as an official reference for use by third party tooling.
10+
11+
## 📜 Problem Statement
12+
13+
Third party GraphQL tooling and libraries may wish to refer to a field, or set of
14+
fields in a schema. Use cases include documentation, metrics and logging
15+
libraries.
16+
17+
![](https://i.fluffy.cc/5Cz9cpwLVsH1FsSF9VPVLwXvwrGpNh7q.png)
18+
19+
_(Example shown from GraphiQL's documentation search tab)_
20+
21+
There already exists a convention used by some third party libraries for writing
22+
out fields in a unique way for such purposes. However, there is no formal
23+
specification or name for this convention.
24+
25+
### Use cases
26+
27+
1. A GraphQL server wants to **log how often each field in the schema is
28+
requested**. This may be implemented by incrementing a counter by the name of
29+
the schema coordinate for each field executed in a request.
30+
31+
_Existing implementations: Yelp (internal), Facebook (internal)_
32+
33+
1. GraphiQL and other playgrounds / documentation sites want to show a list of
34+
**search results** when a user searches for a type or field name. We can
35+
display a list of schema coordinates that match the search term. A schema
36+
coordinate can also be used in the hyperlink to form a permalink for
37+
documentation for a particular field.
38+
39+
_Existing implementations: GraphiQL, Apollo Studio (see "Prior Art")_
40+
41+
1. A developer may want to perform **analytics** on all known
42+
[persisted queries][apq] - e.g. what are the most commonly used fields across
43+
all documents. Schema selectors may be used as the index/lookup keys when
44+
storing this information in the database.
45+
46+
_Existing implementations: Yelp (internal)_
47+
48+
[apq]: https://www.apollographql.com/docs/apollo-server/performance/apq/
49+
50+
1. A **GitHub bot** may want to warn developers in a Pull Request comment
51+
whenever the schema diff contains a breaking change. Schema selectors can be
52+
used to provide a list of which fields were broken.
53+
54+
_Existing implementations: GraphQL Inspector (see "Prior Art")_
55+
56+
1. **GraphQL IDEs** (e.g. GraphiQL, GraphQL Playground, Apollo Studio) may wish
57+
to display the schema definition type of a node in a query when hovering over
58+
it.
59+
60+
<details>
61+
<summary>Example</summary>
62+
![](https://i.fluffy.cc/g78sJCjCJ0MsbNPhvgPXP46Kh9knBCKF.png)
63+
</details>
64+
65+
Schema coordinates can be used to form the left hand side of this popover.
66+
67+
_Existing implementations: Apollo Studio (see "Prior Art")_
68+
69+
## 🚫 What this RFC does _not_ propose
70+
71+
- This does not cover "selectors" or "wildcard" syntax - e.g. `User.*`. _(See
72+
alternatives considered.)_
73+
- There are **no proposed GraphQL language/syntax changes**
74+
- There are **no proposed GraphQL runtime changes**
75+
76+
## ✨ Worked Examples
77+
78+
For example, consider the following schema:
79+
80+
```graphql
81+
type Person {
82+
name: String
83+
}
84+
85+
type Business {
86+
name: String
87+
owner: Person
88+
}
89+
90+
type Query {
91+
searchBusinesses(name: String): [Business]
92+
}
93+
```
94+
95+
We can write the following list of Schema Coordinates:
96+
97+
- `Person` uniquely identifies the the "Person" type
98+
- `Business` uniquely identifies the the "Business" type
99+
- `Person.name` uniquely identifies the "name" field on the "Person" type
100+
- `Business.name` uniquely identifies the "name" field on the "Business"
101+
type
102+
- `Business.owner` uniquely identifies the "owner" field on the "Business" type
103+
- `Query.searchBusinesses` uniquely identifies the "searchBusinesses" field on
104+
the "Query" type
105+
- `Query.searchBusinesses(name)` uniquely identifies the "name" argument on the
106+
"searchBusinesses" field on the "Query" type
107+
108+
This RFC standardizes how we write coordinates GraphQL Schema members as above.
109+
110+
## 🎨 Prior art
111+
112+
- The name "schema coordinates" is inspired from [GraphQL Java](https://github.com/graphql-java/graphql-java)
113+
(4.3k stars), where "field coordinates" are already used in a similar way as
114+
described in this RFC.
115+
116+
- [GitHub comment](https://github.com/graphql/graphql-spec/issues/735#issuecomment-646979049)
117+
- [Implementation](https://github.com/graphql-java/graphql-java/blob/2acb557474ca73/src/main/java/graphql/schema/FieldCoordinates.java)
118+
119+
- GraphiQL displays schema coordinates in its documentation search tab:
120+
121+
![](https://i.fluffy.cc/5Cz9cpwLVsH1FsSF9VPVLwXvwrGpNh7q.png)
122+
123+
- [GraphQL Inspector](https://github.com/kamilkisiela/graphql-inspector) (840
124+
stars) shows schema coordinates in its output:
125+
126+
![](https://i.imgur.com/HAf18rz.png)
127+
128+
- [Apollo Studio](https://www.apollographql.com/docs/studio/) shows schema
129+
coordinates when hovering over fields in a query:
130+
131+
![](https://i.fluffy.cc/g78sJCjCJ0MsbNPhvgPXP46Kh9knBCKF.png)
132+
133+
## 🥣 Document -> Schema Coordinate serialization
134+
135+
Use cases 3 and 5 above imply that a mapping from GraphQL query nodes to schema
136+
coordinates is performed.
137+
138+
For example, consider the following schema:
139+
140+
```graphql
141+
type Person {
142+
name: String
143+
}
144+
145+
type Business {
146+
name: String
147+
owner: Person
148+
}
149+
150+
type Query {
151+
searchBusiness(name: String): [Business]
152+
}
153+
```
154+
155+
And the following query:
156+
157+
```graphql
158+
query {
159+
searchBusinesses(name: "El Greco Deli") {
160+
name
161+
owner {
162+
name
163+
}
164+
}
165+
}
166+
```
167+
168+
From the query above, we may calculate the following list of schema coordinates:
169+
170+
- `Query.searchBusinesses`
171+
- `Business.name`
172+
- `Business.owner`
173+
- `Person.name`
174+
175+
_`Query.searchBusinesses(name)` is also a valid member of the output set. The
176+
serialization algorithm may optionally choose to output all permutations of field
177+
arguments used, should this be specified._
178+
179+
A library has been written to demonstrate this mapping: https://github.com/sharkcore/extract-field-coordinates.
180+
181+
TODO: Should we specify an algorithm for this?
182+
183+
## 🗳️ Alternatives considered
184+
185+
### Naming
186+
187+
- **"Schema Selectors"**
188+
189+
"Selectors" is a term used in [HTML](https://www.w3.org/TR/selectors-api/) and
190+
[CSS](https://drafts.csswg.org/selectors-4/) to _select_ parts of an HTML
191+
document.
192+
193+
This would be a compelling, familiar choice - however, "selector" implies
194+
multiple ways of _selecting_ a schema node (e.g. `User.address` and `User.a*`
195+
might also resolve to `User.address`. But `User.a*` could also ambiguously
196+
refer to `User.age`.
197+
198+
It's unclear how wildcard expansion would work with respect to field
199+
arguments\*, potentially violating the requirement of this schema to _uniquely_
200+
identify schema components.
201+
202+
\* _(e.g. does `Query.getUser` also select all arguments on the `getUser`
203+
field? Who knows! A discussion for another time.)_
204+
205+
A more general purpose schema selector language could be built on top of this
206+
spec - however, we'll consider this **out of scope** for now.
207+
208+
- **"type/field pairs"**
209+
210+
This was the original working name. However, there already exists more
211+
established terminology for this concept, and we also wish to describe more
212+
than just types on fields.
213+
214+
- **"Field Coordinates"**
215+
216+
"Field Coordinates" is already understood and used by the popular
217+
[GraphQL Java](https://github.com/graphql-java/graphql-java) project.
218+
219+
[Feedback in the August GraphQL Working Group meeting](https://youtu.be/FYF15RA9H3k?t=3786)
220+
hinted that since we're targeting also describing arguments, _field_
221+
coordinates might not be the right name. Hence "Schema Coordinates" is chosen
222+
instead, as a more generalized form of this.
223+
224+
- **"GraphQL Coordinates"**
225+
226+
Similar to Field Coordinates/Schema Coordinates - however, "GraphQL
227+
Coordinates" is potentially ambiguous as to if it describes _schema_ members,
228+
_query/document_ members or response object members.
229+
230+
- **"Field path" / "GraphQL path"**
231+
232+
[`path` exists as an attribute on `GraphQLResolveInfo`](https://github.com/graphql/graphql-js/blob/8f3d09b54260565/src/type/definition.js#L951).
233+
234+
Given the following query:
235+
236+
```graphql
237+
query {
238+
searchBusinesses(name: "El Greco Deli") {
239+
name
240+
owner {
241+
name
242+
}
243+
}
244+
}
245+
```
246+
247+
Person.name` in the response may as written as the following "field path":
248+
249+
```json
250+
["query", "searchBusinesses", 1, "owner", "name"]
251+
```
252+
253+
Note that here, the "path" is a serialized _response_ tree traversal, instead
254+
of describing the location of the field in the _schema_.
255+
256+
Since "path" is already used in GraphQL nonclemanture to describe the location
257+
of a field in a response, we'll avoid overloading this term.
258+
259+
### Separator
260+
261+
This RFC proposes using "`.`" as the separator character between a type and
262+
field. The following have also been proposed:
263+
264+
- `Foo::bar`
265+
- `Foo#bar`
266+
- `Foo->bar`
267+
- `Foo~bar`
268+
- `Foo:bar`
269+
270+
"`.`" is already used in the existing implementations of field coordinates, hence
271+
the suggested usage in this RFC. However, we may wish to consider one of the
272+
alternatives above, should this conflict with existing or planned language
273+
features.
274+
275+
## 🤔 Drawbacks / Open questions
276+
277+
- https://github.com/graphql/graphql-spec/issues/735 discusses potential
278+
conflicts with the upcoming namespaces proposal - would like to seek clarity on
279+
this
280+
281+
- Should we specify an algorithm for doing the query -> set of schema
282+
coordinates? Or just hint/imply that this mapping theoretically exists? Is this
283+
out of scope?
284+
285+
### Answered questions
286+
287+
- **Is this extensible enough?** The above issue discusses adding arguments as
288+
part of this specifcation - we haven't touched on this here in order to keep
289+
this RFC small, but we may wish to consider this in the future (e.g.
290+
`Query.searchBusiness:name`).
291+
292+
_Update:_ As discussed in the [August Working Group Meeting][notes], this RFC
293+
now includes the ability to select field arguments
294+
295+
[notes]: https://github.com/graphql/graphql-wg/blob/master/notes/2020-08-06.md#field-coordinates-rfc-15m-mark
296+
297+
- **Would we want to add a method to graphql-js?** A `fieldCoordinateToFieldNode`
298+
method (for example) may take in a field coordinate string and return a field
299+
AST node to serve as a helper / reference implementation of the algorithm to
300+
look up the field node.
301+
302+
_Update:_ [This was discussed in the August Working Group Meeting][meeting] -
303+
it was suggested to keep any utilities as third party libraries to avoid edge
304+
ambiguity problems, and to be able to iterate faster.
305+
306+
[meeting]: https://youtu.be/FYF15RA9H3k?t=2865
307+
308+
## TODOs:
309+
310+
- Write the formal specification as a draft section in the schema

0 commit comments

Comments
 (0)