-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
377 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
# RFC: Field Coordinate Serialization | ||
|
||
_This is a sister RFC to [RFC: Field Coordinates](./FieldCoordinates.md). This | ||
document assumes knowledge of the Field Coordinates RFC._ | ||
|
||
This RFC outlines the seralization of field nodes in a GraphQL query to ["field | ||
coordinates"](./FieldCoordinates.md). | ||
|
||
## 📜 Problem Statement | ||
|
||
Third party GraphQL tooling and libraries may wish to refer to a field, or set of | ||
fields refered to in a document (e.g. query, mutation or subscription). Use cases include documentation, metrics and logging libraries. | ||
|
||
![](https://i.fluffy.cc/g78sJCjCJ0MsbNPhvgPXP46Kh9knBCKF.png) | ||
|
||
_(Field coordinates shown in a query - [Apollo Studio](https://www.apollographql.com/docs/studio/)_) | ||
|
||
There already exists a convention used by some third party libraries for | ||
calculating field coordinates in a query. However, there is no formal | ||
specification or name for this convention. | ||
|
||
This RFC proposes standardization for computing field coordinates. | ||
|
||
## 🐕 Worked Example | ||
|
||
Consier the following schema: | ||
|
||
```graphql | ||
type Person { | ||
name: String | ||
} | ||
|
||
type Business { | ||
name: String | ||
owner: String | ||
} | ||
|
||
type Query { | ||
searchBusiness(name: String): [Business] | ||
} | ||
``` | ||
|
||
And the following query: | ||
|
||
```graphql | ||
query { | ||
searchBusinesses(name: "El Greco Deli") { | ||
name | ||
owner { | ||
name | ||
} | ||
} | ||
} | ||
``` | ||
|
||
A GraphQL server may wish to log which fields are accessed in a query, such that | ||
we can compute a list of "most popular fields" in the schema. We may then want to | ||
use this list to optimize the most frequently accessed fields in our schea. | ||
|
||
Field coordinates allow us to store this list of "most popular fields". | ||
|
||
We want a way to calculate field coordinates from a given field node (and by | ||
extension, calculate a list of all field coordinates contained in a document). | ||
|
||
From the query above, we would calculate the following list of field coordinates: | ||
|
||
- `Query.searchBusinesses` | ||
- `Business.name` | ||
- `Business.owner` | ||
- `Person.name` | ||
|
||
## Examples in industry | ||
|
||
- [Apollo Studio](https://www.apollographql.com/docs/studio/) shows field | ||
coodinates when hovering over fields in a query: | ||
|
||
![](https://i.fluffy.cc/g78sJCjCJ0MsbNPhvgPXP46Kh9knBCKF.png) | ||
|
||
- [extract-field-coordinates](https://github.com/sharkcore/extract-field-coordinates) | ||
extracts a list of field coordinates from a schema and query document. | ||
|
||
## Drawbacks | ||
|
||
- Requires the corresponding schema as an input to be able to calculate the field | ||
coordinate | ||
|
||
- **Edge Cases:** There are some edge cases where we need to decide (or let the | ||
user decide) behaviour: | ||
|
||
- What happens when the schema is outdated or a type referenced in the query is | ||
not present in the schema? Do we throw an error as the document/schema is | ||
invalid, or do we try a "best effort" approach to preserve as much information | ||
as possible? | ||
|
||
- TODO: add more edge case behaviour from the [sample implementation](https://github.com/sharkcore/extract-field-coordinates) | ||
|
||
## Alternatives Considered | ||
|
||
### Field Paths | ||
|
||
[`path` exists as an attribute on `GraphQLResolveInfo`](https://github.com/graphql/graphql-js/blob/8f3d09b54260565/src/type/definition.js#L951). | ||
|
||
Given the following query: | ||
|
||
```graphql | ||
query { | ||
searchBusinesses(name: "El Greco Deli") { | ||
name | ||
owner { | ||
name | ||
} | ||
} | ||
} | ||
``` | ||
|
||
The field coordinate `Person.name` may also be written as the following field | ||
path: | ||
|
||
```json | ||
["query", "searchBusinesses", 1, "owner", "name"] | ||
``` | ||
|
||
- Like field coordinates, this uniquely identifies the "name" field and | ||
disambiguates it from the "name" field on the `Business` type. | ||
- Note that we also didn't need a schema to calculate the field path - this can | ||
be with just the query document. | ||
|
||
However - we are unable to tell from a field path alone what the parent _type_ | ||
was. | ||
|
||
Consider the following query: | ||
|
||
```graphql | ||
query { | ||
getUsers(name: "mark") { | ||
name | ||
} | ||
} | ||
``` | ||
|
||
The same field coordinate `Person.name` in the context of this query would be | ||
written as: | ||
|
||
```json | ||
["query", "getUsers", 1, "name"] | ||
``` | ||
|
||
Field Paths alone are insufficient to do normalization of the field nodes. We | ||
need the parent type information from the schema to work out that both of these | ||
field paths reference the same field in the schema. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
# RFC: Field Coordinates | ||
|
||
**Champion:** @magicmark | ||
|
||
This RFC proposes formalizing "field coordinates" - a way to uniquely identify a | ||
field defined in a GraphQL Schema. | ||
|
||
This may be listed as an appendix item in the official specification to serve as | ||
an official reference to third party library implementations. | ||
|
||
## 🚫 What this RFC does _not_ propose | ||
|
||
This RFC does not seek to change the GraphQL language in any way. | ||
|
||
- There are **no proposed GraphQL runtime changes** | ||
- There are **no proposed changes to how we parse documents**. | ||
|
||
## 📜 Problem Statement | ||
|
||
Third party GraphQL tooling and libraries may wish to refer to a field, or set of | ||
fields in a schema. Use cases include documentation, metrics and logging | ||
libraries. | ||
|
||
![](https://i.fluffy.cc/5Cz9cpwLVsH1FsSF9VPVLwXvwrGpNh7q.png) | ||
|
||
_(Example shown from GraphiQL's documentation search tab)_ | ||
|
||
There already exists a convention used by some third party libraries for writing | ||
out fields in a unique way for such purposes. However, there is no formal | ||
specification or name for this convention. | ||
|
||
## ✨ Worked Example | ||
|
||
For example, consider the following schema: | ||
|
||
```graphql | ||
type Person { | ||
name: String | ||
} | ||
|
||
type Business { | ||
name: String | ||
owner: String | ||
} | ||
|
||
type Query { | ||
searchBusinesses(name: String): [Business] | ||
} | ||
``` | ||
|
||
We can write the following list of field coordinates: | ||
|
||
- `Person.name` uniquely identifies the "name" field on the "Person" type | ||
- `Business.name` uniquely identifies the "name" field on the "Business" | ||
type | ||
- `Business.owner` uniquely identifies the "owner" field on the "Business" type | ||
- `Query.searchBusinesses` uniquely identifies the "searchBusinesses" field on | ||
the "Query" type | ||
|
||
This RFC standardizes how we write field coodinates as above. | ||
|
||
## 🎨 Prior art | ||
|
||
- The name "field coordinates" comes from [GraphQL Java](https://github.com/graphql-java/graphql-java) | ||
(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) | ||
|
||
- GraphiQL displays field coordinates in its documentation search tab: | ||
|
||
![](https://i.fluffy.cc/5Cz9cpwLVsH1FsSF9VPVLwXvwrGpNh7q.png) | ||
|
||
- [GraphQL Inspector](https://github.com/kamilkisiela/graphql-inspector) (840 stars) shows type/field pairs in its output: | ||
|
||
![](https://i.imgur.com/HAf18rz.png) | ||
|
||
- [Apollo Studio](https://www.apollographql.com/docs/studio/) shows field | ||
coodinates when hovering over fields in a query: | ||
|
||
![](https://i.fluffy.cc/g78sJCjCJ0MsbNPhvgPXP46Kh9knBCKF.png) | ||
|
||
## 🗳️ Alternatives considered | ||
|
||
### Naming | ||
|
||
- "type/field pairs" was the original suggestion | ||
|
||
However, "field coordinates" was chosen as it is already understood and used by | ||
by the popular [GraphQL Java](https://github.com/graphql-java/graphql-java) | ||
project. | ||
|
||
### Seperator | ||
|
||
This RFC proposes using "`.`" as the seperator character. The following have also | ||
been proposed: | ||
|
||
- `Foo::bar` | ||
- `Foo#bar` | ||
- `Foo->bar` | ||
- `Foo~bar` | ||
- `Foo:bar` | ||
|
||
"`.`" is already used in the existing implemenations of field coordinates, hence | ||
the suggested usage in this RFC. However, we may wish to consider one of the | ||
alternatives above, should this conflict with existing or planned language | ||
features. | ||
|
||
## 🤔 Drawbacks / Open questions | ||
|
||
- https://github.com/graphql/graphql-spec/issues/735 discusses potential | ||
conflicts with the upcoming namspaces proposal - would like to seek clarity on | ||
this | ||
|
||
- **Is this extensible enough?** The above issue discusses adding arguments as | ||
part of this specifcation - we haven't touched on this here in order to keep | ||
this RFC small, but we may wish to consider this in the future (e.g. | ||
`Query.searchBusiness:name`). | ||
|
||
- **How will this play with namespaces?** Not sure what this looks like yet! | ||
|
||
- **Would we want to add a method to graphql-js?** A `fieldCoordinateToFieldNode` | ||
method (for example) may take in a field coordinate string and return a field | ||
AST node to serve as a helper / reference implementation of the algorithm to | ||
look up the field node. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
# C. Tooling Conventions | ||
|
||
This specification document formalizes naming and conventions that may be used by | ||
GraphQL tooling and third party libraries. | ||
|
||
|
||
## Field Coordinates | ||
|
||
FieldCoordinate : TypeName `.` FieldName | ||
|
||
A field coordinate may be used to uniquely identify a field in a GraphQL schema. | ||
It is encoded as a string containing a dot seperated parent type and field pair. | ||
|
||
**Examples** | ||
|
||
Consider the following schema: | ||
|
||
```graphql example | ||
type Person { | ||
name: String | ||
age: Int | ||
} | ||
|
||
type Business { | ||
name: String | ||
owner: Person | ||
} | ||
``` | ||
|
||
In order to refer to the `name` field on the `Business` type, we would write the | ||
following field coordinate: | ||
|
||
```example | ||
Business.name | ||
``` | ||
|
||
Simiarly, in order to refer to the `name` field on the `Person` type, we would | ||
write the following field coordinate: | ||
|
||
```example | ||
Person.name | ||
``` | ||
|
||
**Formal Specification** | ||
|
||
* Split the field coordinate string by {`.`} | ||
* Let {typeName} and {fieldName} be the zeroth and first results respectively | ||
* {typeName} must be defined in the schema as a {Name} attribute of {ObjectTypeDefinition} | ||
* {fieldName} must be defined as a {Name} attribute in a {FieldDefinition} of the {FieldsDefinition} attribute of the {ObjectTypeDefinition} found above | ||
|
||
## Converting a FieldNode to a Field Coordinate | ||
|
||
Given a matching schema, we may wish to refer to a field used in a query document | ||
using a field coordinate. | ||
|
||
**Example** | ||
|
||
Consider the following schema: | ||
|
||
```graphql example | ||
type Person { | ||
name: String | ||
age: Int | ||
} | ||
|
||
type Business { | ||
name: String | ||
owner: Person | ||
} | ||
|
||
type Query { | ||
searchBusinesses(name: String): [Business] | ||
} | ||
``` | ||
|
||
Also consider the following document: | ||
|
||
```graphql example | ||
query { | ||
searchBusinesses(name: "El Greco Deli") { | ||
name | ||
owner { | ||
name | ||
} | ||
} | ||
} | ||
``` | ||
|
||
We can calculate that the list of field coordinates referenced in this query is | ||
as follows: | ||
|
||
```example | ||
Query.searchBusinesses | ||
Business.name | ||
Business.owner | ||
Person.name | ||
``` | ||
|
||
**Formal Specification** | ||
|
||
TODO: Write up an algorithm | ||
|
||
(code implementation: https://github.com/sharkcore/extract-field-coordinates/blob/master/src/extract-field-paths.js) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters