Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions spec/Appendix C -- Grammar Summary.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ Digit :: one of

- `0` `1` `2` `3` `4` `5` `6` `7` `8` `9`

QualifiedName ::

- QualifiedName . Name [lookahead != `.`]
- Name . Name [lookahead != `.`]

IntValue :: IntegerPart [lookahead != {Digit, `.`, NameStart}]

IntegerPart ::
Expand Down Expand Up @@ -248,6 +253,7 @@ TypeSystemDefinition :
- SchemaDefinition
- TypeDefinition
- DirectiveDefinition
- ServiceDefinition

TypeSystemExtensionDocument : TypeSystemDefinitionOrExtension+

Expand All @@ -260,6 +266,7 @@ TypeSystemExtension :

- SchemaExtension
- TypeExtension
- ServiceExtension

SchemaDefinition : Description? schema Directives[Const]? {
RootOperationTypeDefinition+ }
Expand Down Expand Up @@ -414,6 +421,19 @@ TypeSystemDirectiveLocation : one of
- `INPUT_OBJECT`
- `INPUT_FIELD_DEFINITION`

ServiceDefinition : Description? service Directives? { ServiceCapability\* }

ServiceExtension :

- extend service Directives? { ServiceCapability\* }
- extend service Directives [lookahead != `{`]

ServiceCapability :

- Description? capability QualifiedName ServiceCapabilityValue?

ServiceCapabilityValue : ( StringValue )

## Schema Coordinate Syntax

Note: Schema coordinates must not contain {Ignored}.
Expand Down
12 changes: 12 additions & 0 deletions spec/Section 2 -- Language.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,18 @@ Any {Name} within a GraphQL type system must not start with two underscores
{"\_\_"} unless it is part of the [introspection system](#sec-Introspection) as
defined by this specification.

### Qualified Names

QualifiedName ::

- QualifiedName . Name [lookahead != `.`]
- Name . Name [lookahead != `.`]

A qualified name is a case-sensitive string composed of two or more names
separated by a period (`.`). A qualified name allows for a structured chain of
names which can be useful for scoping or applying namespaces. A _capability
identifier_ is an example of a {QualifiedName}.

## Descriptions

Description : StringValue
Expand Down
131 changes: 131 additions & 0 deletions spec/Section 3 -- Type System.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ TypeSystemDefinition :
- SchemaDefinition
- TypeDefinition
- DirectiveDefinition
- ServiceDefinition

The GraphQL language includes an
[IDL](https://en.wikipedia.org/wiki/Interface_description_language) used to
Expand Down Expand Up @@ -40,6 +41,7 @@ TypeSystemExtension :

- SchemaExtension
- TypeExtension
- ServiceExtension

Type system extensions are used to represent a GraphQL type system which has
been extended from some previous type system. For example, this might be used by
Expand Down Expand Up @@ -2321,3 +2323,132 @@ input UserUniqueCondition @oneOf {
organizationAndEmail: OrganizationAndEmailInput
}
```

## Service Definition

ServiceDefinition : Description? service Directives? { ServiceCapability\* }

A GraphQL service is defined in terms of the capabilities that it offers which
are external to the schema.

### Service Capabilities

ServiceCapability : Description? capability QualifiedName
ServiceCapabilityValue?

ServiceCapabilityValue : ( StringValue )
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not

ServiceCapabilityArgument : ArgumentName: ConstantValue
ServiceCapabilityValue : ( ServiceCapabilityArgument+ )

Basically: why shouldn't we be able to use enum values or integers or have a service take in an input or etc? Seems like it'd be common to need 3-4 flags for one capability to work.

Copy link
Member Author

@benjie benjie Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we don't yet have the struct type which would be ideal for this.

But also, if you need multiple arguments (why?) either use custom serialization or use multiple capabilities.

service {
  capability graphql.ws
  capability graphql.ws.endpoint("ws://...")

  "To avoid thundering herd, multiply this by `(0.5 + rand())`"
  capability graphql.ws.reconnectDelay("3000")

  "The modern protocol"
  capability graphql.ws.protocol.graphqlTransportWs

  "The updated modern protocol"
  capability graphql.ws.protocol.graphqlTransportWs.v2

  "Configuration for V2 protocol"
  capability graphql.ws.protocol.graphqlTransportWs.v2.encoding("utf-8")

  "The legacy protocol"
  capability graphql.ws.protocol.graphqlWs
}

Arguments should be the rarer case, IMO - if in doubt, use a sub-name (like the protocols above) rather than an argument.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have examples that don't fit this well?


:: A _service capability_ describes a feature supported by the GraphQL service
but not directly expressible via the type system. This may include support for
new or experimental GraphQL syntactic or behavioral features, protocol support
(such as GraphQL over WebSockets or Server-Sent Events), or additional
operational information (such as endpoints for related services). Service
capabilities may be supplied by the GraphQL implementation, the service, or
both.

A _service capability_ is identified by a _capability identifier_ (a
{QualifiedName}), and may optionally have a string value. All capabilities
within a service must have unique identifiers.

```graphql example
service {
"Descriptions on operations and fragments are supported"
capability graphql.operationDescriptions

"Websocket transport is supported via the given endpoint"
capability example.transport.ws("wss://api.example.com/graphql")
}
```

**Capability Identifier**

:: A _capability identifier_ is a {QualifiedName} (a case-sensitive string value
composed of two or more {Name} separated by a period (`.`)) that uniquely
identifies a capability. This structure is inspired by reverse domain notation
to encourage global uniqueness and collision-resistance; it is recommended that
identifiers defined by specific projects, vendors, or implementations begin with
a prefix derived from a DNS name they control (e.g., {"com.example."}).

Clients must compare capability identifiers using exact (case-sensitive) string
equality.

**Reserved Capability Identifiers**

A _capability identifier_ must not start with an underscore {"\_"}; this is
reserved for future usage.

Capability identifiers beginning with the prefix {"graphql."} are reserved and
must not be used outside of official GraphQL Foundation specifications.
Identifiers beginning with the prefix {"graphql.rfc."} are reserved for RFC
proposals.

Any identifiers beginning with case-insensitive variants of {"graphql."},
{"org.graphql."} and {"gql."} are also reserved.

Identifiers beginning with the prefix {"example."} are reserved for usage in
documentation and examples only.

Note: Since IANA RFC 2606 reserves the second-level domain names
{"example.com"}, {"example.net"}, and {"example.org"} for documentation
purposes, the corresponding reverse-domain prefixes {"com.example."},
{"net.example."}, and {"org.example."} are also reserved for documentation
purposes.

Implementers should not change the meaning of capability identifiers; instead, a
new capability identifier should be used when the meaning changes. Implementers
should ensure that capability identifiers remain stable and version-agnostic
where possible.

Note: Capability versioning, if needed, can be indicated using dot suffixes
(e.g. {"example.capability.v2"}).

This system enables incremental feature adoption and richer tooling
interoperability, while avoiding tight coupling to specific implementations.

**Capability value**

For capabilities that require more information than a simple indication of
support, a string value may be specified.

For example, the capability {"graphql.operationDescriptions"} does not require
additional information and thus does not specify a value; whereas a capability
such as {"example.transport.ws"} might use the value to indicate the endpoint to
use for websocket communications (or might omit a value to indicate that
WebSockets are supported at the current endpoint).

**Specified capabilities**

This version of the specification defines the following capabilities:

- {"graphql.operationDescriptions"} - indicates support for descriptions on
operations and fragments

### Service Extension

ServiceExtension :

- extend service Directives? { ServiceCapability\* }
- extend service Directives [lookahead != `{`]

Service extensions are used to represent a service which has been extended from
a previous service. For example, this might be used by a GraphQL service which
adds additional capabilities to an existing service.

Note: Service extensions without additional capability definitions must not be
followed by a {`{`} (such as a query shorthand) to avoid parsing ambiguity.

```graphql example
extend service {
capability example.newCapability
}
```

**Service Validation**

Service extensions have the potential to be invalid if incorrectly defined.

1. The Service must already be defined.
2. Any non-repeatable directives provided must not already apply to the previous
Service.
3. Any capabilities provided must not already be defined on the previous
Service.
43 changes: 40 additions & 3 deletions spec/Section 4 -- Introspection.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,14 @@ operation.

## Schema Introspection

The schema introspection system is accessible from the meta-fields `__schema`
and `__type` which are accessible from the type of the root of a query
operation.
The schema introspection system is accessible from the meta-fields `__schema`,
`__type` and `__service` which are accessible from the type of the root of a
query operation.

```graphql
__schema: __Schema!
__type(name: String!): __Type
__service: __Service!
```

Like all meta-fields, these are implicit and do not appear in the fields list in
Expand Down Expand Up @@ -228,6 +229,16 @@ enum __DirectiveLocation {
INPUT_OBJECT
INPUT_FIELD_DEFINITION
}

type __Service {
capabilities: [__Capability!]!
}

type __Capability {
identifier: String!
description: String
value: String
}
```

### The \_\_Schema Type
Expand Down Expand Up @@ -512,3 +523,29 @@ Fields\:
{true}, deprecated arguments are also returned.
- `isRepeatable` must return a Boolean that indicates if the directive may be
used repeatedly at a single location.

### The \_\_Service Type

The `__Service` type is returned from the `__service` meta-field and provides
information about the GraphQL service, most notably about its capabilities.

Note: Services implementing an older version of this specification may not
support the `__service` meta-field or `__Service` type. Support may be probed
using the introspection query: `{ __type(name: "__Service") { name } }`, a
{null} result indicates lack of support.

Fields\:

- `capabilities` must return a list of `__Capability` detailing each _service
capability_ supported by the service.

### The \_\_Capability Type

A `__Capability` object describes a specific _service capability_, and has the
following fields\:

- `identifier` must return the string _capability identifier_ uniquely
identifying this service capability.
- `description` may return a String or {null}.
- `value` the String value of the service capability, or {null} if there is no
associated value.