Skip to content

Commit 858a105

Browse files
committed
RFC: Field coordinates
1 parent 478adf3 commit 858a105

File tree

4 files changed

+377
-0
lines changed

4 files changed

+377
-0
lines changed

rfcs/FieldCoodinateSerialization.md

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# RFC: Field Coordinate Serialization
2+
3+
_This is a sister RFC to [RFC: Field Coordinates](./FieldCoordinates.md). This
4+
document assumes knowledge of the Field Coordinates RFC._
5+
6+
This RFC outlines the seralization of field nodes in a GraphQL query to ["field
7+
coordinates"](./FieldCoordinates.md).
8+
9+
## 📜 Problem Statement
10+
11+
Third party GraphQL tooling and libraries may wish to refer to a field, or set of
12+
fields refered to in a document (e.g. query, mutation or subscription). Use cases include documentation, metrics and logging libraries.
13+
14+
![](https://i.fluffy.cc/g78sJCjCJ0MsbNPhvgPXP46Kh9knBCKF.png)
15+
16+
_(Field coordinates shown in a query - [Apollo Studio](https://www.apollographql.com/docs/studio/)_)
17+
18+
There already exists a convention used by some third party libraries for
19+
calculating field coordinates in a query. However, there is no formal
20+
specification or name for this convention.
21+
22+
This RFC proposes standardization for computing field coordinates.
23+
24+
## 🐕 Worked Example
25+
26+
Consier the following schema:
27+
28+
```graphql
29+
type Person {
30+
name: String
31+
}
32+
33+
type Business {
34+
name: String
35+
owner: String
36+
}
37+
38+
type Query {
39+
searchBusiness(name: String): [Business]
40+
}
41+
```
42+
43+
And the following query:
44+
45+
```graphql
46+
query {
47+
searchBusinesses(name: "El Greco Deli") {
48+
name
49+
owner {
50+
name
51+
}
52+
}
53+
}
54+
```
55+
56+
A GraphQL server may wish to log which fields are accessed in a query, such that
57+
we can compute a list of "most popular fields" in the schema. We may then want to
58+
use this list to optimize the most frequently accessed fields in our schea.
59+
60+
Field coordinates allow us to store this list of "most popular fields".
61+
62+
We want a way to calculate field coordinates from a given field node (and by
63+
extension, calculate a list of all field coordinates contained in a document).
64+
65+
From the query above, we would calculate the following list of field coordinates:
66+
67+
- `Query.searchBusinesses`
68+
- `Business.name`
69+
- `Business.owner`
70+
- `Person.name`
71+
72+
## Examples in industry
73+
74+
- [Apollo Studio](https://www.apollographql.com/docs/studio/) shows field
75+
coodinates when hovering over fields in a query:
76+
77+
![](https://i.fluffy.cc/g78sJCjCJ0MsbNPhvgPXP46Kh9knBCKF.png)
78+
79+
- [extract-field-coordinates](https://github.com/sharkcore/extract-field-coordinates)
80+
extracts a list of field coordinates from a schema and query document.
81+
82+
## Drawbacks
83+
84+
- Requires the corresponding schema as an input to be able to calculate the field
85+
coordinate
86+
87+
- **Edge Cases:** There are some edge cases where we need to decide (or let the
88+
user decide) behaviour:
89+
90+
- What happens when the schema is outdated or a type referenced in the query is
91+
not present in the schema? Do we throw an error as the document/schema is
92+
invalid, or do we try a "best effort" approach to preserve as much information
93+
as possible?
94+
95+
- TODO: add more edge case behaviour from the [sample implementation](https://github.com/sharkcore/extract-field-coordinates)
96+
97+
## Alternatives Considered
98+
99+
### Field Paths
100+
101+
[`path` exists as an attribute on `GraphQLResolveInfo`](https://github.com/graphql/graphql-js/blob/8f3d09b54260565/src/type/definition.js#L951).
102+
103+
Given the following query:
104+
105+
```graphql
106+
query {
107+
searchBusinesses(name: "El Greco Deli") {
108+
name
109+
owner {
110+
name
111+
}
112+
}
113+
}
114+
```
115+
116+
The field coordinate `Person.name` may also be written as the following field
117+
path:
118+
119+
```json
120+
["query", "searchBusinesses", 1, "owner", "name"]
121+
```
122+
123+
- Like field coordinates, this uniquely identifies the "name" field and
124+
disambiguates it from the "name" field on the `Business` type.
125+
- Note that we also didn't need a schema to calculate the field path - this can
126+
be with just the query document.
127+
128+
However - we are unable to tell from a field path alone what the parent _type_
129+
was.
130+
131+
Consider the following query:
132+
133+
```graphql
134+
query {
135+
getUsers(name: "mark") {
136+
name
137+
}
138+
}
139+
```
140+
141+
The same field coordinate `Person.name` in the context of this query would be
142+
written as:
143+
144+
```json
145+
["query", "getUsers", 1, "name"]
146+
```
147+
148+
Field Paths alone are insufficient to do normalization of the field nodes. We
149+
need the parent type information from the schema to work out that both of these
150+
field paths reference the same field in the schema.

rfcs/FieldCoordinates.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# RFC: Field Coordinates
2+
3+
**Champion:** @magicmark
4+
5+
This RFC proposes formalizing "field coordinates" - a way to uniquely identify a
6+
field defined in a GraphQL Schema.
7+
8+
This may be listed as an appendix item in the official specification to serve as
9+
an official reference to third party library implementations.
10+
11+
## 🚫 What this RFC does _not_ propose
12+
13+
This RFC does not seek to change the GraphQL language in any way.
14+
15+
- There are **no proposed GraphQL runtime changes**
16+
- There are **no proposed changes to how we parse documents**.
17+
18+
## 📜 Problem Statement
19+
20+
Third party GraphQL tooling and libraries may wish to refer to a field, or set of
21+
fields in a schema. Use cases include documentation, metrics and logging
22+
libraries.
23+
24+
![](https://i.fluffy.cc/5Cz9cpwLVsH1FsSF9VPVLwXvwrGpNh7q.png)
25+
26+
_(Example shown from GraphiQL's documentation search tab)_
27+
28+
There already exists a convention used by some third party libraries for writing
29+
out fields in a unique way for such purposes. However, there is no formal
30+
specification or name for this convention.
31+
32+
## ✨ Worked Example
33+
34+
For example, consider the following schema:
35+
36+
```graphql
37+
type Person {
38+
name: String
39+
}
40+
41+
type Business {
42+
name: String
43+
owner: String
44+
}
45+
46+
type Query {
47+
searchBusinesses(name: String): [Business]
48+
}
49+
```
50+
51+
We can write the following list of field coordinates:
52+
53+
- `Person.name` uniquely identifies the "name" field on the "Person" type
54+
- `Business.name` uniquely identifies the "name" field on the "Business"
55+
type
56+
- `Business.owner` uniquely identifies the "owner" field on the "Business" type
57+
- `Query.searchBusinesses` uniquely identifies the "searchBusinesses" field on
58+
the "Query" type
59+
60+
This RFC standardizes how we write field coodinates as above.
61+
62+
## 🎨 Prior art
63+
64+
- The name "field coordinates" comes from [GraphQL Java](https://github.com/graphql-java/graphql-java)
65+
(4.3k stars), where this is already used as described - [Github comment](https://github.com/graphql/graphql-spec/issues/735#issuecomment-646979049) - [Implementation](https://github.com/graphql-java/graphql-java/blob/2acb557474ca73/src/main/java/graphql/schema/FieldCoordinates.java)
66+
67+
- GraphiQL displays field coordinates in its documentation search tab:
68+
69+
![](https://i.fluffy.cc/5Cz9cpwLVsH1FsSF9VPVLwXvwrGpNh7q.png)
70+
71+
- [GraphQL Inspector](https://github.com/kamilkisiela/graphql-inspector) (840 stars) shows type/field pairs in its output:
72+
73+
![](https://i.imgur.com/HAf18rz.png)
74+
75+
- [Apollo Studio](https://www.apollographql.com/docs/studio/) shows field
76+
coodinates when hovering over fields in a query:
77+
78+
![](https://i.fluffy.cc/g78sJCjCJ0MsbNPhvgPXP46Kh9knBCKF.png)
79+
80+
## 🗳️ Alternatives considered
81+
82+
### Naming
83+
84+
- "type/field pairs" was the original suggestion
85+
86+
However, "field coordinates" was chosen as it is already understood and used by
87+
by the popular [GraphQL Java](https://github.com/graphql-java/graphql-java)
88+
project.
89+
90+
### Seperator
91+
92+
This RFC proposes using "`.`" as the seperator character. The following have also
93+
been proposed:
94+
95+
- `Foo::bar`
96+
- `Foo#bar`
97+
- `Foo->bar`
98+
- `Foo~bar`
99+
- `Foo:bar`
100+
101+
"`.`" is already used in the existing implemenations of field coordinates, hence
102+
the suggested usage in this RFC. However, we may wish to consider one of the
103+
alternatives above, should this conflict with existing or planned language
104+
features.
105+
106+
## 🤔 Drawbacks / Open questions
107+
108+
- https://github.com/graphql/graphql-spec/issues/735 discusses potential
109+
conflicts with the upcoming namspaces proposal - would like to seek clarity on
110+
this
111+
112+
- **Is this extensible enough?** The above issue discusses adding arguments as
113+
part of this specifcation - we haven't touched on this here in order to keep
114+
this RFC small, but we may wish to consider this in the future (e.g.
115+
`Query.searchBusiness:name`).
116+
117+
- **How will this play with namespaces?** Not sure what this looks like yet!
118+
119+
- **Would we want to add a method to graphql-js?** A `fieldCoordinateToFieldNode`
120+
method (for example) may take in a field coordinate string and return a field
121+
AST node to serve as a helper / reference implementation of the algorithm to
122+
look up the field node.
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# C. Tooling Conventions
2+
3+
This specification document formalizes naming and conventions that may be used by
4+
GraphQL tooling and third party libraries.
5+
6+
7+
## Field Coordinates
8+
9+
FieldCoordinate : TypeName `.` FieldName
10+
11+
A field coordinate may be used to uniquely identify a field in a GraphQL schema.
12+
It is encoded as a string containing a dot seperated parent type and field pair.
13+
14+
**Examples**
15+
16+
Consider the following schema:
17+
18+
```graphql example
19+
type Person {
20+
name: String
21+
age: Int
22+
}
23+
24+
type Business {
25+
name: String
26+
owner: Person
27+
}
28+
```
29+
30+
In order to refer to the `name` field on the `Business` type, we would write the
31+
following field coordinate:
32+
33+
```example
34+
Business.name
35+
```
36+
37+
Simiarly, in order to refer to the `name` field on the `Person` type, we would
38+
write the following field coordinate:
39+
40+
```example
41+
Person.name
42+
```
43+
44+
**Formal Specification**
45+
46+
* Split the field coordinate string by {`.`}
47+
* Let {typeName} and {fieldName} be the zeroth and first results respectively
48+
* {typeName} must be defined in the schema as a {Name} attribute of {ObjectTypeDefinition}
49+
* {fieldName} must be defined as a {Name} attribute in a {FieldDefinition} of the {FieldsDefinition} attribute of the {ObjectTypeDefinition} found above
50+
51+
## Converting a FieldNode to a Field Coordinate
52+
53+
Given a matching schema, we may wish to refer to a field used in a query document
54+
using a field coordinate.
55+
56+
**Example**
57+
58+
Consider the following schema:
59+
60+
```graphql example
61+
type Person {
62+
name: String
63+
age: Int
64+
}
65+
66+
type Business {
67+
name: String
68+
owner: Person
69+
}
70+
71+
type Query {
72+
searchBusinesses(name: String): [Business]
73+
}
74+
```
75+
76+
Also consider the following document:
77+
78+
```graphql example
79+
query {
80+
searchBusinesses(name: "El Greco Deli") {
81+
name
82+
owner {
83+
name
84+
}
85+
}
86+
}
87+
```
88+
89+
We can calculate that the list of field coordinates referenced in this query is
90+
as follows:
91+
92+
```example
93+
Query.searchBusinesses
94+
Business.name
95+
Business.owner
96+
Person.name
97+
```
98+
99+
**Formal Specification**
100+
101+
TODO: Write up an algorithm
102+
103+
(code implementation: https://github.com/sharkcore/extract-field-coordinates/blob/master/src/extract-field-paths.js)

spec/GraphQL.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,5 @@ Note: This is an example of a non-normative note.
128128
# [Appendix: Notation Conventions](Appendix%20A%20--%20Notation%20Conventions.md)
129129

130130
# [Appendix: Grammar Summary](Appendix%20B%20--%20Grammar%20Summary.md)
131+
132+
# [Appendix: Tooling Conventions](Appendix%20C%20--%20Tooling%20Conventions.md)

0 commit comments

Comments
 (0)