Schema Coordinates
At a glance
- Identifier: SchemaCoordinates
- Stage: RFC0: Strawman
- Champion: -
- PR: -
- Related:
- #733 (Tagged type)
- #794 (Schema Coordinates)
- FieldExtensions (Field Extensions)
Timeline
- RFC document updated on 2024-02-08 by Benjie
- RFC document created on 2021-01-07 by Mark Larah
RFC: Schema Coordinates
Proposed by: Mark Larah - Yelp
Spec pull request: https://github.com/graphql/graphql-spec/pull/794
This RFC proposes formalizing "Schema Coordinates" - a human readable syntax to uniquely identify a type, field, field argument, enum value, directive or directive argument defined in a GraphQL Schema.
This should be listed as a non-normative note in the GraphQL specification to serve as an official reference for use by third party tooling.
📜 Problem Statement
GraphQL tooling and libraries may wish to refer to various components of a GraphQL schema. Use cases include documentation, metrics and logging libraries.
(Example shown from GraphiQL's documentation search tab)
There already exists a convention used by some libraries and tools for writing out fields in a unique way for such purposes. However, there is no formal specification or name for this convention.
Use cases
A GraphQL server wants to log how often each field in the schema is requested. This may be implemented by incrementing a counter by the name of the schema coordinate for each field executed in a request.
Existing implementations: Yelp (internal), Facebook (internal), Shopify (API health report)
GraphiQL and other playgrounds / documentation sites want to show a list of search results when a user searches for a type or field name. We can display a list of schema coordinates that match the search term. A schema coordinate can also be used in the hyperlink to form a permalink for documentation for a particular field.
Existing implementations: GraphiQL, Apollo Studio (see "Prior Art")
A developer may want to perform analytics on all known persisted queries - e.g. what are the most commonly used fields across all documents. Schema coordinates may be used as the index/lookup keys when storing this information in the database.
Existing implementations: Yelp (internal)
A GitHub bot may want to warn developers in a Pull Request comment whenever the schema diff contains a breaking change. Schema coordinates can be used to provide a list of which fields were broken.
Existing implementations: GraphQL Inspector (see "Prior Art")
GraphQL IDEs (e.g. GraphiQL, GraphQL Playground, Apollo Studio) may wish to display the schema definition type of a node in a query when hovering over it.
Details
Example
Schema coordinates can be used to form the left hand side of this popover.
Existing implementations: Apollo Studio (see "Prior Art")
✅ RFC Goals
- There be one, unambiguous way to write a "schema coordinate" that refers to a particular element in a GraphQL schema. (This is to avoid users having to "simplify" more complex coordinates to produce a canonical representation.)
- Schema coordinate syntax should build off of existing de-facto standards already adopted for this purpose (i.e.
Foo.bar
)- Schema coordinate syntax is open for extension in the future. We should make design choices that give us flexibility and anticipate future syntax needs (based off of discussions around this RFC).
🚫 RFC Non-goals
- This does not cover "selectors" or "wildcard" syntax - e.g.
User.*
. (See alternatives considered.)- There are no proposed GraphQL language/syntax changes
- There are no proposed GraphQL runtime changes
- Schema coordinate non-goals
🧑💻 Proposed syntax
Type
Refers to a named type (e.g. something represented by
__typename
in a GraphQL introspection call).
Type.attribute
Refers to a named attribute on the named type.
Not all types support this. For object types and interface types this is a field, for input objects this would be an input field, for enums this would be an enum value, for future GraphQL types this will relate to a related concept if they have one (e.g. for the proposed "tagged" type it would refer to the "member field").
Type.field(argName:)
Refers to a named argument on the named field of the named type.
@directive
References the given named directive
@directive(argName:)
References the named argument of the named directive.
✨ Examples
For example, consider the following schema:
directive @private(scope: String!) on FIELD
type Person {
name: String
email: String @private(scope: "loggedIn")
}
type Business {
name: String
owner: Person
}
type Query {
searchBusinesses(name: String): [Business]
}We can write the following schema coordinates:
Person
uniquely identifies the the "Person" typeBusiness
uniquely identifies the the "Business" typePerson.name
uniquely identifies the "name" field on the "Person" typeBusiness.name
uniquely identifies the "name" field on the "Business" typeBusiness.owner
uniquely identifies the "owner" field on the "Business" typeQuery.searchBusinesses
uniquely identifies the "searchBusinesses" field on the "Query" typeQuery.searchBusinesses(name:)
uniquely identifies the "name" argument on the "searchBusinesses" field on the "Query" type@private
uniquely identifies the "private" directive@private(scope:)
uniquely identifies the "scope" argument on the "private" directive🎨 Prior art