From 4de5de67a4c2c97f9c614b9c4cb7deb2f315fda3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 1 Aug 2024 18:28:21 +0000 Subject: [PATCH] deploy: 9cafeefcc12090a48fe9223ccd2285313a3ba232 --- draft/index.html | 2890 +++------------------------------------------- index.html | 2 +- 2 files changed, 142 insertions(+), 2750 deletions(-) diff --git a/draft/index.html b/draft/index.html index 083a4e9..02a1d27 100644 --- a/draft/index.html +++ b/draft/index.html @@ -64,90 +64,26 @@
3Supergraph -
  • 4Composition
      -
    1. 4.1Validate
        -
      1. 4.1.1Types
          -
        1. 4.1.1.1Semantical Equivalence
        2. +
        3. 3Schema Composition
            +
          1. 3.1Validate Source Schema
          2. +
          3. 3.2Merge Source Schemas
              +
            1. 3.2.1Pre Merge Validation
            2. +
            3. 3.2.2Merge
            4. +
            5. 3.2.3Post Merge Validation
          4. -
          5. 4.1.2Composite Types
              -
            1. 4.1.2.1Field Types Mergeable
            2. -
            3. 4.1.2.2Argument Types Mergeable
            4. -
            5. 4.1.2.3Arguments mergeable
            6. -
            7. 4.1.2.4Required Arguments Cannot Be Internal
            8. -
            9. 4.1.2.5Public Fields Cannot Reference Internals
            10. +
            11. 3.3Validate Satisfiability
          6. -
          7. 4.1.3Object Types
              -
            1. 4.1.3.1Empty Merged Object Type
            2. +
            3. 4Executor
                +
              1. 4.1Configuration
            4. -
            5. 4.1.4Input Object Types
                -
              1. 4.1.4.1Input Field Types mergeable
              2. -
              3. 4.1.4.2Input With Different Fields
              4. -
              5. 4.1.4.3Empty Merged Input Object Type
              6. -
              7. 4.1.4.4Input Field Default Mismatch
              8. -
              9. 4.1.4.5Public Input Fields Cannot Reference Internals
              10. -
              11. 4.1.4.6Required Input Fields cannot be internal
              12. +
              13. 5Shared Types
                  +
                1. 5.1Name
                2. +
                3. 5.2FieldSelection
              14. -
              15. 4.1.5Enum Types
                  -
                1. 4.1.5.1Values Must Be The Same Across Subgraphs
                2. -
                3. 4.1.5.2Default Value Uses Internals
                4. -
                5. 4.1.5.3Empty Merged Enum Type
                6. -
                -
              16. -
              17. 4.1.6Interface
                  -
                1. 4.1.6.1Empty Merged Interface Type
                2. -
                -
              18. -
              19. 4.1.7Union
                  -
                1. 4.1.7.1Union Type Members Cannot Reference Internals
                2. -
                -
              20. -
              21. 4.1.8Schema
                  -
                1. 4.1.8.1No Queries
                2. -
                -
              22. -
              23. 4.1.9Shared Functions
                  -
                1. 4.1.9.1Same Type Shape
                2. -
                3. 4.1.9.2Is Exposed
                4. -
                -
              24. -
              -
            6. -
            7. 4.2Compose
                -
              1. 4.2.1MergeObjectType
              2. -
              3. 4.2.2MergeInputType
              4. -
              5. 4.2.3MergeInterfaceType
              6. -
              7. 4.2.4MergeUnionType
              8. -
              9. 4.2.5MergeEnumType
              10. -
              11. 4.2.6MergeInputField
              12. -
              13. 4.2.7MergeOutputField
              14. -
              15. 4.2.8MergeArguments
              16. -
              17. 4.2.9MergeArgument
              18. -
              19. 4.2.10MergeInterfaceImplementation
              20. -
              21. 4.2.11MergeInputFieldType
              22. -
              23. 4.2.12MergeOutputFieldType
              24. -
              25. 4.2.13EnsureNonNullType
              26. -
              27. 4.2.14EnsureNullableType
              28. -
              29. 4.2.15ToListType
              30. -
              -
            8. -
            9. 4.3Satisfiability
            10. -
            -
          8. -
          9. 5Executor
              -
            1. 5.1Configuration
            2. -
            -
          10. -
          11. 6Shared Types
              -
            1. 6.1Name
            2. -
            3. 6.2FieldSelection
            4. -
            -
          12. -
          13. §Index
          @@ -159,7 +95,7 @@

          Composable: Rather than defining each source schema in isolation and reshaping it to fit the composite schema later, this specification encourages developers to design the source schemas as part of a larger whole from the start. Each source schema defines the types and fields it is responsible for serving within the context of the larger schema, referencing and extending that which is provided by other source schemas. The GraphQL Composite Schemas specification does not describe how to combine arbitrary schemas.

        4. Collaborative: The GraphQL Composite Schemas specification is explicitly designed around team collaboration. By building on a principled composition model, it ensures that conflicts and inconsistencies are surfaced early and can be resolved before deployment. This allows many teams to contribute to a single schema without the danger of breaking it. The GraphQL Composite Schemas specification facilitates the coordinated effort of combining collaboratively designed source schemas into a single coherent composite schema.
        5. -
        6. Evolvable: A composite schema offers an integrated, product-centric API interface to clients. Each source GraphQL service that underpins the composite schema should be able to evolve without disrupting these clients. Over time, the same functionality may be provided by a different combination of services, while the composite schemas interface must continue to support existing requests from all clients; source schema boundaries are therefore considered an implementation detail and should never be exposed to clients.
        7. +
        8. Evolvable: A composite schema enables offering an integrated, product-centric API interface to clients; source schema boundaries are an implementation detail, a detail that is not exposed to clients. As each underlying GraphQL service evolves, the same functionality may be provided from a different combination of services. This specification helps to ensure that changes to underlying services can be made whilst maintaining support for existing requests from all clients to the composite schema interface.
        9. Explicitness: To make the composition process easier to understand and to avoid ambiguities that can lead to confusing failures as the system grows, the GraphQL Composite Schemas specification prefers to be explicit about intentions and minimize reliance on inference and convention.
        10. To enable greater interoperability between different implementations of tooling and gateways, this specification focuses on two core components: schema composition and distributed execution.

          @@ -170,16 +106,14 @@

          2Source Schema

          -

          The GraphQL Composite Schemas spec refers to downstream GraphQL APIs that have been designed for composition as subgraphs. These subgraphs may have additional directives specified in this section to indicate semantics of type system members in the overall graph.

          -

          2.1Directives

          -

          Subgraph directives offer instructions for the schema composition process, detailing type system member semantics and specifying type transformations. In some cases subgraph schemas can be composed without any directives.

          +

          2.1Directives

          -

          2.1.1@entityResolver

          -
          directive @entityResolver on FIELD_DEFINITION
          +

          2.1.1@entityResolver

          +
          directive @entityResolver on FIELD_DEFINITION
           
          -

          Entity resolvers are fields on the query root type of a subgraph that can resolve an entity by a stable key. The stable key is defined by the arguments of the field.

          -
          Example № 3extend type Query {
          +

          Entity resolvers are fields on the query root type of a subgraph that can resolve an entity by a stable key. The stable key is defined by the arguments of the field.

          +
          Example № 3extend type Query {
             version: Int # NOT an entity resolver.
             personById(id: ID!): Person @entityResolver
           }
          @@ -188,8 +122,8 @@ 

          id: ID! # matches the argument of personById }

          -

          The arguments of an entity resolver field must match fields of the returning type.

          -
          Example № 4extend type Query {
          +

          The arguments of an entity resolver field must match fields of the returning type.

          +
          Example № 4extend type Query {
             node(id: ID!): Node @entityResolver
           }
           
          @@ -197,8 +131,8 @@ 

          id: ID! }

          -

          When an entity resolver returns an interface all implementing types are inferred as entities.

          -
          Example № 5extend type Query {
          +

          When an entity resolver returns an interface all implementing types are inferred as entities.

          +
          Example № 5extend type Query {
             entityById(id: ID!, categoryId: Int): Entity @entityResolver
           }
           
          @@ -216,39 +150,39 @@ 

          -

          2.1.2@is

          -
          directive @is(
          +

          2.1.2@is

          +
          directive @is(
             field: FieldSelection
             coordinate: Schemacoordinate
           ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION
           
          -

          The @is directive is utilized to establish semantic equivalence between disparate type system members across distinct subgraphs, which the schema composition uses to connect types.

          -

          In the following example, the directive specifies that the id argument on the field Query.personById and the field Person.id on the return type of the field are semantically the same. This information is used to infer an entity resolver for Person from the field Query.personById.

          -
          Example № 6extend type Query {
          +

          The @is directive is utilized to establish semantic equivalence between disparate type system members across distinct subgraphs, which the schema composition uses to connect types.

          +

          In the following example, the directive specifies that the id argument on the field Query.personById and the field Person.id on the return type of the field are semantically the same. This information is used to infer an entity resolver for Person from the field Query.personById.

          +
          Example № 6extend type Query {
             personById(id: ID! @is(field: "id")): Person @entityResolver
           }
           
          -

          The @is directive also allows to refer to nested fields relative to Person.

          -
          Example № 7extend type Query {
          +

          The @is directive also allows to refer to nested fields relative to Person.

          +
          Example № 7extend type Query {
             personByAddressId(id: ID! @is(field: "address { id }")): Person
           }
           
          -

          The @is directive not limited to a single argument.

          -
          Example № 8extend type Query {
          +

          The @is directive not limited to a single argument.

          +
          Example № 8extend type Query {
             personByAddressId(
               id: ID! @is(field: "address { id }")
               kind: PersonKind @is(field: "kind")
             ): Person
           }
           
          -

          The directive can also establish semantic equivalence between two output fields. In this example, the field productSKU is semantically equivalent to the field Product.sku, allowing the schema composition to infer the connection of the Product with the Review type.

          -
          Example № 9extend type Review {
          +

          The directive can also establish semantic equivalence between two output fields. In this example, the field productSKU is semantically equivalent to the field Product.sku, allowing the schema composition to infer the connection of the Product with the Review type.

          +
          Example № 9extend type Review {
             productSKU: ID! @is(coordinate: "Product.sku") @internal
             product: Product @resolve
           }
           
          -

          The @is directive can use either the field or coordinate argument. If both are specified, the schema composition must fail.

          -
          Counter Example № 10extend type Review {
          +

          The @is directive can use either the field or coordinate argument. If both are specified, the schema composition must fail.

          +
          Counter Example № 10extend type Review {
             productSKU: ID!
               @is(coordinate: "Product.sku", field: "product { sku }")
               @internal
          @@ -256,32 +190,32 @@ 

          }

          -
          Arguments:
          +
          Arguments:
            -
          • field: Represents a GraphQL field selection syntax that refers to field relative to the current type; or, when used on arguments it refers to a field relative to the return type.
          • -
          • coordinate: Represents a schema coordinate that refers to a type system member.
          • +
          • field: Represents a GraphQL field selection syntax that refers to field relative to the current type; or, when used on arguments it refers to a field relative to the return type.
          • +
          • coordinate: Represents a schema coordinate that refers to a type system member.

          -

          2.1.3@shareable

          -
          directive @shareable repeatable on OBJECT | FIELD_DEFINITION
          +

          2.1.3@shareable

          +
          directive @shareable repeatable on OBJECT | FIELD_DEFINITION
           
          -

          By default, only one subgraph is allowed to contribute a particular field to an object type. This prevents subgraphs from inadvertently defining similarly named fields that are semantically not the same.

          -

          Fields have to be explicitly marked as @shareable to allow multiple subgraphs to define it. And it ensures the step of allowing a field to be served from multiple subgraphs is an explicit, coordinated decision.

          -

          If multiple subgraphs define the same field, these are assumed to be semantically equivalent, and the executor is free to choose between them as it sees fit.

          -
          +

          By default, only one subgraph is allowed to contribute a particular field to an object type. This prevents subgraphs from inadvertently defining similarly named fields that are semantically not the same.

          +

          Fields have to be explicitly marked as @shareable to allow multiple subgraphs to define it. And it ensures the step of allowing a field to be served from multiple subgraphs is an explicit, coordinated decision.

          +

          If multiple subgraphs define the same field, these are assumed to be semantically equivalent, and the executor is free to choose between them as it sees fit.

          +
          Note Key fields are always considered sharable.
          -

          2.1.4@require

          -
          directive @require(
          +

          2.1.4@require

          +
          directive @require(
             field: FieldSelection!
           ) on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION
           
          -

          The @require directive is used to express data requirements with other subgraphs. Arguments annotated with the @require directive are removed from the public exposed schema and the value for these will be resolved by the executor.

          -
          Example № 11type Product {
          +

          The @require directive is used to express data requirements with other subgraphs. Arguments annotated with the @require directive are removed from the public exposed schema and the value for these will be resolved by the executor.

          +
          Example № 11type Product {
             id: ID!
             delivery(
               zip: String!
          @@ -290,8 +224,8 @@ 

          ): DeliveryEstimates }

          -

          This can also be done by using input types. All fields of the input type that match the required output type are required. If the input type is only used to express a requirement it is removed from the public schema.

          -
          Example № 12type Product {
          +

          This can also be done by using input types. All fields of the input type that match the required output type are required. If the input type is only used to express a requirement it is removed from the public schema.

          +
          Example № 12type Product {
             id: ID!
             delivery(
               zip: String!
          @@ -301,2686 +235,144 @@ 

          -

          2.1.5@provides

          -
          directive @provides(fields: SelectionSet!) on FIELD_DEFINITION
          +

          2.1.5@provides

          +
          directive @provides(fields: SelectionSet!) on FIELD_DEFINITION
           
          -

          The @provides directive is an optimization hint specifying child fields that can be resolved locally at the given subgraph through a particular query path. This allows for a variation of overlapping field to improve data fetching.

          +

          The @provides directive is an optimization hint specifying child fields that can be resolved locally at the given subgraph through a particular query path. This allows for a variation of overlapping field to improve data fetching.

          -

          2.1.6@external

          -
          directive @external on OBJECT_DEFINITION | INTERFACE_DEFINITION | FIELD_DEFINITION
          +

          2.1.6@external

          +
          directive @external on OBJECT_DEFINITION | INTERFACE_DEFINITION | FIELD_DEFINITION
           
          -

          The @external directive is used in combination with the @provides directive and specifies data that is not owned ba a particular subgraph.

          +

          The @external directive is used in combination with the @provides directive and specifies data that is not owned ba a particular subgraph.

          -

          2.1.7@override

          -
          directive @override(from: String!) on FIELD_DEFINITION
          +

          2.1.7@override

          +
          directive @override(from: String!) on FIELD_DEFINITION
           
          -

          The @override directive allows to migrate fields from one subgraph to another.

          +

          The @override directive allows to migrate fields from one subgraph to another.

          -

          2.1.8@internal

          -
          directive @internal on OBJECT | INTERFACE | FIELD_DEFINITION | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCALAR
          +

          2.1.8@internal

          +
          directive @internal on OBJECT | INTERFACE | FIELD_DEFINITION | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCALAR
           
          -

          The @internal directive signals to the composition process that annotated type system members shall not be included into the public schema but still can be used by the executor to build resolvers.

          +

          The @internal directive signals to the composition process that annotated type system members shall not be included into the public schema but still can be used by the executor to build resolvers.

          -

          2.1.9Schemacoordinate

          -
          scalar Schemacoordinate
          -
          -

          The Schemacoordinate scalar represents a schema coordinate syntax.

          -
          Example № 13Product.id
          -
          -
          Example № 14Product.estimateDelivery(zip:)
          -
          -
          -
          - -
          -

          3Supergraph

          -
          -
          -

          4Composition

          -

          The composition of subgraphs describes the process of merging multiple subgraph schemas into a single GraphQL schema that is annotated with execution directives. This single GraphQL schema is the output of the Schema Composition and represents the Gateway Configuration. The schema composition process is divided into four algorithms, Validate, Compose, and Finalize that are run in order.

          -
          -

          4.1Validate

          -

          A GraphQL Composite Schemas spec composition tool ensures that the provided subgraph schemas are unambiguous and mistake-free in the context of the composed supergraph. The aim here is to guarantee that a composed supergraph will have no query errors due to an inconsistent schemas.

          -

          A request against an inconsistent supergraph is still technically executable, and will always produce a stable result as defined by the algorithms in the Execution section, however that result may be ambiguous, surprising, or unexpected relative to a request containing validation errors, so a composition tool must ensure that subgraphs involved in the supergraph allow for consistent query planning during execution.

          -

          Typically validation is performed in the context of the composition.

          -
          -

          4.1.1Types

          -
          -

          4.1.1.1Semantical Equivalence

          -
          -
          Error Code
          -

          F0001

          -
          -
          -
          Formal Specification
          -
            -
          • Let typesByName be the set of all types across all subgraphs involved in the schema composition by their given type name.
          • -
          • Given each pair of types typeA and typeB in typesByName
              -
            • typeA and typeB must have the same kind
            • -
            -
          • -
          -
          -
          -
          Explanatory Text
          -

          GraphQL Composite Schemas spec considers types with the same name across subgraphs as semantically equivalent and mergeable.

          -

          Types that do not have the same kind are considered not mergeable.

          -
          Example № 15type User {
          -  id: ID!
          -  name: String!
          -  displayName: String!
          -  birthdate: String!
          -}
          -
          -type User {
          -  id: ID!
          -  name: String!
          -  reviews: [Review!]
          -}
          -
          -
          Example № 16scalar DateTime
          -
          -scalar DateTime
          -
          -
          Counter Example № 17type User {
          -  id: ID!
          -  name: String!
          -  displayName: String!
          -  birthdate: String!
          -}
          -
          -scalar User
          -
          -
          Counter Example № 18enum UserKind {
          -  A
          -  B
          -  C
          -}
          -
          -scalar UserKind
          -
          -
          -
          -
          -
          -

          4.1.2Composite Types

          -
          -

          4.1.2.1Field Types Mergeable

          -
          -
          Error Code
          -

          F0002

          -
          -
          -
          Formal Specification
          -
            -
          • Let fieldsByName be a map of field lists where the key is the name of a field and the value is a list of fields from mergeable types from different subgraphs with the same name.
          • -
          • for each fields in fieldsByName -
          • -
          -
          -FieldsAreMergeable(fields)
            -
          1. Given each pair of members fieldA and fieldB in fields:
              -
            1. Let typeA be the type of fieldA
            2. -
            3. Let typeB be the type of fieldB
            4. -
            5. SameTypeShape(typeA, typeB) must be true.
            6. -
            -
          2. -
          -
          -
          -SameTypeShape(typeA, typeB)
            -
          1. If typeA is Non-Null:
              -
            1. If typeB is nullable
                -
              1. Let innerType be the inner type of typeA
              2. -
              3. return SameTypeShape(innerType, typeB)
              4. -
              -
            2. -
            -
          2. -
          3. If typeB is Non-Null:
              -
            1. If typeA is nullable
                -
              1. Let innerType be the inner type of typeB
              2. -
              3. return SameTypeShape(typeA, innerType)
              4. -
              -
            2. -
            -
          4. -
          5. If typeA or typeB is List:
              -
            1. If typeA or typeB is not List, return false.
            2. -
            3. Let innerTypeA be the item type of typeA.
            4. -
            5. Let innerTypeB be the item type of typeB.
            6. -
            7. return SameTypeShape(innerTypeA, innerTypeB)
            8. -
            -
          6. -
          7. If typeA and typeB are not of the same kind
              -
            1. return false
            2. -
            -
          8. -
          9. If typeA and typeB do not have the same name
              -
            1. return false
            2. -
            -
          10. -
          -
          -
          -
          -
          Explanatory Text
          -

          Fields on mergeable objects or interfaces with that have the same name are considered semantically equivalent and mergeable when they have a mergeable field type.

          -

          Fields with the same type are mergeable.

          -
          Example № 19type User {
          -  birthdate: String
          -}
          -
          -type User {
          -  birthdate: String
          -}
          +

          2.1.9Schemacoordinate

          +
          scalar Schemacoordinate
           
          -

          Fields with different nullability are mergeable, resulting in merged field with a nullable type.

          -
          Example № 20type User {
          -  birthdate: String!
          -}
          -
          -type User {
          -  birthdate: String
          -}
          -
          -
          Example № 21type User {
          -  tags: [String!]
          -}
          -
          -type User {
          -  tags: [String]!
          -}
          -
          -type User {
          -  tags: [String]
          -}
          -
          -

          Fields are not mergeable if the named types are different in kind or name.

          -
          Counter Example № 22type User {
          -  birthdate: String!
          -}
          -
          -type User {
          -  birthdate: DateTime!
          -}
          +

          The Schemacoordinate scalar represents a schema coordinate syntax.

          +
          Example № 13Product.id
           
          -
          Counter Example № 23type User {
          -  tags: [Tag]
          -}
          -
          -type Tag {
          -  value: String
          -}
          -
          -type User {
          -  tags: [Tag]
          -}
          -
          -scalar Tag
          +
          Example № 14Product.estimateDelivery(zip:)
           
          -
          -

          4.1.2.2Argument Types Mergeable

          -
          -
          Error Code
          -

          F0004

          -
          -
          Formal Specification
          -
            -
          • Let fieldsByName be a map of field lists where the key is the name of a field and the value is a list of fields from mergeable types from different subgraphs with the same name.
          • -
          • for each fields in fieldsByName
              -
            • if FieldsInSetCanMerge(fields) must be true.
            • -
            -
          • -
          -
          -FieldsAreMergeable(fields)
            -
          1. Given each pair of members fieldA and fieldB in fields:
              -
            1. ArgumentsAremergeable(fieldA, fieldB) must be true.
            2. -
            -
          2. -
          -
          -
          -ArgumentsAremergeable(fieldA, fieldB)
            -
          1. Given each pair of arguments argumentA and argumentB in fieldA and fieldB:
              -
            1. Let typeA be the type of argumentA
            2. -
            3. Let typeB be the type of argumentB
            4. -
            5. SameTypeShape(typeA, typeB) must be true.
            6. -
            -
          2. -
          -
          +
          +

          3Schema Composition

          +

          The schema composition describes the process of merging multiple source schemas into a single GraphQL schema, known as the composite execution schema, which is a valid GraphQL schema annotated with execution directives. This composite execution schema is the output of the schema composition process. The schema composition process is divided into four major algorithms: Validate Source Schema, Merge Source Schema, and Validate Satisfiability, which are run in sequence to produce the composite execution schema.

          +
          +

          3.1Validate Source Schema

          -
          -
          Explanatory Text
          -

          Fields on mergeable objects or interfaces with that have the same name are considered semantically equivalent and mergeable when they have a mergeable argument types.

          -

          Fields when all matching arguments have a mergeable type.

          -
          Example № 24type User {
          -  field(argument: String): String
          -}
          -
          -type User {
          -  field(argument: String): String
          -}
          -
          -

          Arguments that differ on nullability of an argument type are mergeable.

          -
          Example № 25type User {
          -  field(argument: String!): String
          -}
          -
          -type User {
          -  field(argument: String): String
          -}
          -
          -
          Example № 26type User {
          -  field(argument: [String!]): String
          -}
          -
          -type User {
          -  field(argument: [String]!): String
          -}
          -
          -type User {
          -  field(argument: [String]): String
          -}
          -
          -

          Arguments are not mergeable if the named types are different in kind or name.

          -
          Counter Example № 27type User {
          -  field(argument: String!): String
          -}
          -
          -type User {
          -  field(argument: DateTime): String
          -}
          -
          -
          Counter Example № 28type User {
          -  field(argument: [String]): String
          -}
          -
          -type User {
          -  field(argument: [DateTime]): String
          -}
          -
          +
          +

          3.2Merge Source Schemas

          +
          +

          3.2.1Pre Merge Validation

          +
          +

          3.2.2Merge

          -
          -

          4.1.2.3Arguments mergeable

          -
          -
          Error Code
          -

          FXXXX

          +
          +

          3.2.3Post Merge Validation

          -
          -
          Formal Specification
          -
          -
          Explanatory Text
          -
          Example № 29type User {
          -  field(a: String): String
          -}
          -
          -type User {
          -  field(a: String): String
          -}
          -
          -
          Counter Example № 30type User {
          -  field(a: String): String
          -}
          -
          -type User {
          -  field(b: String): String
          -}
          -
          +
          +

          3.3Validate Satisfiability

          -
          -

          4.1.2.4Required Arguments Cannot Be Internal

          -
          -
          Error Code
          -

          F0014

          +
          +

          4Executor

          +

          A distributed GraphQL executor acts as an orchestrator that uses schema metadata to rewrite a GraphQL request into a query plan. This plan resolves the required data from subgraphs and coerces this data into the result of the GraphQL request.

          +
          +

          4.1Configuration

          +

          The supergraph is a GraphQL IDL document that contains metadata for the query planner that describes the relationship between type system members and the type system members on subgraphs.

          -
          -
          Formal Specification
          -
            -
          • Let subgraphs be a list of all subgraphs.
          • -
          • For each subgraph in subgraphs:
              -
            • Let arguments be the set of all arguments in subgraph.
            • -
            • For each argument in arguments:
                -
              • If IsExposed(argument) is false
                  -
                • Let type be the type of argument
                • -
                • type must not be nullable
                • -
                -
              • -
              -
            • -
            -
          • -
          -
          -
          Explanatory Text
          -

          Required arguments of fields or directives (i.e., arguments that are non-nullable) must be exposed in the composed schema. Removing a required argument from the composed schema creates a contradiction where an argument is necessary for the operation in the composed schema but is not available for external use.

          -

          The following example illustrates a valid scenario where a required argument is not marked as @internal:

          -
          Example № 31type Query {
          -  field1(arg1: Int!): [Item]
          -}
          -
          -type Query {
          -  field1(arg1: Int!): [Item]
          -}
          -
          -

          In this counter example, the arg1 argument is essential for field field1 in one of the subgraph and is marked as required, but it is also marked as @internal, violating the rule that required arguments cannot be internal:

          -
          Counter Example № 32type Query {
          -  field1(arg1: Int!): [Item]
          -}
          -
          -type Query {
          -  field1(arg1: Int! @internal): [Item]
          -}
          -
          -

          In this counter example, the arg1 argument is essential for field field1 in one of the subgraph but does not exist in the other subgraph, violating the rule that required arguments cannot be internal:

          -
          Counter Example № 33type Query {
          -  field1(arg1: Int!): [Item]
          -}
          -
          -type Query {
          -  field1: [Item]
          -}
          -
          -

          The same rule applied to directives. The following counter-example illustrate scenario where a directive argument is essential for a directive in one subgraph, but does not exist in the other subgraph:

          -
          Counter Example № 34directive @directive1(arg1: Int!) on FIELD
          -
          -directive @directive1 on FIELD
          +
          +

          5Shared Types

          +

          In this section we outline directives and types that are shared between the subgraph configuration and the gateway configuration document.

          +
          +

          5.1Name

          +
          scalar Name
           
          +

          The scalar Name represents a valid GraphQL type name.

          -
          -
          -

          4.1.2.5Public Fields Cannot Reference Internals

          -
          -
          Error Code
          -

          F0016

          -
          -
          -
          Formal Specification
          -
            -
          • Let subgraphs be a list of all subgraphs.
          • -
          • For each subgraph in subgraphs:
              -
            • Let fields be the set of all fields of the composite types in subgraph
            • -
            • For each field in fields:
                -
              • If IsExposed(field) is true
                  -
                • Let namedType be the named type that field references
                • -
                • IsExposed(namedType) must be true
                • -
                -
              • -
              -
            • -
            -
          • -
          -
          -
          -
          Explanatory Text
          -

          In a composed schema, a field within a composite type must only reference types that are exposed. This requirement guarantees that public types do not reference internal structures which are intended for internal use.

          -

          Here is a valid example where a public field references another public type:

          -
          Example № 35type Object1 {
          -  field1: String!
          -  field2: Object2
          -}
          -
          -type Object2 {
          -  field3: String
          -}
          -
          -type Object1 {
          -  field1: String!
          -  field4: Int
          -}
          -
          -

          This is another valid case where the internal type is not exposed in the composed schema:

          -
          Example № 36type Object1 {
          -  field1: String!
          -  field2: Object2 @internal
          -}
          -
          -type Object2 @internal {
          -  field3: String
          -}
          -
          -type Object1 {
          -  field1: String!
          -  field4: Int
          -}
          +
          +

          5.2FieldSelection

          +
          scalar FieldSelection
           
          -

          However, it becomes invalid if a public field in one subgraph references a type that is marked as @internal in another subgraph:

          -
          Counter Example № 37type Object1 {
          -  field1: String!
          -  field2: Object2
          -}
          -
          -type Object2 {
          -  field3: String
          -}
          -
          -type Object1 {
          -  field1: String!
          -  field2: Object2 @internal
          -}
          -
          -type Object2 @internal {
          -  field3: String
          -  field5: Int
          -}
          +

          The scalar FieldSelection represents a GraphQL field selection syntax.

          +
          Example № 15abc(def: 1) { ghi }
           
          -
          -
          -

          4.1.3Object Types

          -
          -

          4.1.3.1Empty Merged Object Type

          -
          -
          Error Code
          -

          F0019

          -
          -
          -
          Formal Specification
          -
            -
          • Let types be the set of all object types across all subgraphs
          • -
          • For each type in types: -
          • -
          -
          -IsObjectTypeEmpty(type)
            -
          1. Let fields be a set of all fields of all types with coordinate and kind type across all subgraphs
          2. -
          3. For each field in fields:
              -
            1. If IsExposed(field) is true
                -
              1. return false
              2. + + + +
          -
          -
          Explanatory Text
          -

          For object types defined across multiple subgraphs, the merged object type is the superset of all fields defined in these subgraphs. However, any field marked with @internal in any subgraph is hidden and not included in the merged object type. An object type with no fields, after considering @internal markings, is considered empty and invalid.

          -

          In the following example, the merged object type ObjectType1 is valid. It includes all fields from both subgraphs, with field2 being hidden due to the @internal directive in one of the subgraphs:

          -
          type ObjectType1 {
          -  field1: String
          -  field2: Int @internal
          -}
          -
          -type ObjectType1 {
          -  field1: String
          -  field2: Int
          -  field3: Boolean
          -}
          -
          -

          This counter-example demonstrates an invalid merged object type. In this case, ObjectType1 is defined in two subgraphs, but all fields are marked as @internal in at least one of the subgraphs, resulting in an empty merged object type:

          -
          Counter Example № 38type ObjectType1 {
          -  field1: String @internal
          -  field2: Boolean
          -}
          -
          -type ObjectType1 {
          -  field1: String
          -  field2: Boolean @internal
          -}
          -
          -
          -
          -
          -
          -

          4.1.4Input Object Types

          -
          -

          4.1.4.1Input Field Types mergeable

          -
          -
          Error Code
          -

          F0005

          -
          -
          -
          Formal Specification
          -
            -
          • Let fieldsByName be a map of field lists where the key is the name of a field and the value is a list of fields from mergeable input types from different subgraphs with the same name.
          • -
          • For each fields in fieldsByName:
          • -
          -
          -InputFieldsAremergeable(fields)
            -
          1. Given each pair of members fieldA and fieldB in fields:
              -
            1. Let typeA be the type of fieldA.
            2. -
            3. Let typeB be the type of fieldB.
            4. -
            5. SameTypeShape(typeA, typeB) must be true.
            6. +
            7. 3.3Validate Satisfiability
          2. -
          -
          -
          -
          -
          Explanatory Text
          -

          The input fields of input objects with the same name must be mergeable. This rule ensures that input objects with the same name in different subgraphs have fields that can be consistently merged without conflict.

          -

          Input fields are considered mergeable when they share the same name and have compatible types. The compatibility of types is determined by their structure (lists), excluding nullability. mergeable input fields with different nullability are considered mergeable, and the resulting merged field will be the most permissive of the two.

          -

          In this example, the field field in Input1 has compatible types across subgraphs, making them mergeable:

          -
          Example № 39input Input1 {
          -  field: String!
          -}
          -
          -input Input1 {
          -  field: String
          -}
          -
          -

          Here, the field tags in Input1 is a list type with compatible inner types, satisfying the mergeable criteria:

          -
          Example № 40input Input1 {
          -  tags: [String!]
          -}
          -
          -input Input1 {
          -  tags: [String]!
          -}
          -
          -input Input1 {
          -  tags: [String]
          -}
          -
          -

          In this counter-example, the field field in Input1 has incompatible types (String and DateTime), making them not mergeable:

          -
          Counter Example № 41input Input1 {
          -  field: String!
          -}
          -
          -input Input1 {
          -  field: DateTime!
          -}
          -
          -

          Here, the field tags in Input1 is a list type with incompatible inner types (String and DateTime), violating the mergeable rule:

          -
          Counter Example № 42input Input1 {
          -  tags: [String]
          -}
          -
          -input Input1 {
          -  tags: [DateTime]
          -}
          -
          -
          -
          -
          -

          4.1.4.2Input With Different Fields

          -
          -
          Error Code
          -

          F0006

          -
          -
          -
          Formal Specification
          -
            -
          • Let inputsByName be a map where the key is the name of an input object type, and the value is a list of all input object types from different subgraphs with that name.
          • -
          • For each listOfInputs in inputsByName: -
          • -
          -
          -InputFieldsAremergeable(inputs)
            -
          1. Let fields be the set of all field names of the first input object in inputs.
          2. -
          3. For each input in inputs:
              -
            1. Let inputFields be the set of all field names of input.
            2. -
            3. fields must be equal to inputFields.
            4. -
            -
          4. -
          -
          -
          -
          -
          Explanatory Text
          -

          This rule ensures that input object types with the same name across different subgraphs have identical sets of field names. Consistency in input object fields across subgraphs is required to avoid conflicts and ambiguities in the composed schema. This rule only checks that the field names are the same, not that the field types are the same. Field types are checked by the Input Field Types mergeable rule.

          -

          When an input object is defined with differing fields across subgraphs, it can lead to issues in query execution. A field expected in one subgraph might be absent in another, leading to undefined behavior. This rule prevents such inconsistencies by enforcing that all instances of the same named input object across subgraphs have a matching set of field names.

          -

          In this example, both subgraphs define Input1 with the same field field1, satisfying the rule:

          -
          Example № 43input Input1 {
          -  field1: String
          -}
          -
          -input Input1 {
          -  field1: String
          -}
          -
          -

          Here, the two definitions of Input1 have different fields (field1 and field2), violating the rule:

          -
          Counter Example № 44input Input1 {
          -  field1: String
          -}
          -
          -input Input1 {
          -  field2: String
          -}
          -
          -
          -
          -
          -

          4.1.4.3Empty Merged Input Object Type

          -
          -
          Error Code
          -

          F0010

          -
          -
          -
          Formal Specification
          -
            -
          • Let inputs be the set of all input object types across all subgraphs
          • -
          • For each input in inputs: -
          • -
          -
          -IsInputObjectTypeEmpty(input)
            -
          1. Let fields be a set of all input fields across all subraphs with coordinate input
          2. -
          3. For each field in fields:
              -
            1. If IsExposed(field) is true
                -
              1. return false
              2. -
              -
            2. -
            -
          4. -
          -
          -
          -
          -
          Explanatory Text
          -

          When an input object type is defined in multiple subgraphs, only common fields and fields not flagged as @internal are included in the merged input object type. If this process results in an input object type with no fields, the input object type is considered empty and invalid.

          -

          In the following example, the merged input object type Input1 is valid. The type is defined in two subgraphs:

          -
          input Input1 {
          -  field1: String @internal
          -  field2: Int
          -}
          -
          -input Input1 {
          -  field1: String
          -  field2: Int
          -}
          -
          -

          In the following example, the merged input object type Input1 is valid and contains field1 as it exists in both subgraphs. The type is defined in two subgraphs:

          -
          input Input1 {
          -  field1: String
          -}
          -
          -input Input1 {
          -  field1: String
          -  field2: Int
          -}
          -
          -

          In the following example, the merged input object type Input1 is invalid. The type is defined in two subgraphs, but do not have any common fields.

          -
          Counter Example № 45input Input1 {
          -  field1: String
          -}
          -
          -input Input1 {
          -  field2: String
          -}
          -
          -

          This counter-example shows an invalid merged input object type. The Input1 type is defined in two subgraphs, but both field1 and field2 are flagged as @internal in one of the subgraphs:

          -
          Counter Example № 46input Input1 {
          -  field1: String @internal
          -  field2: Int @internal
          -}
          -
          -input Input1 {
          -  field1: String
          -  field2: Int
          -}
          -
          -

          In this counter-example, the Input1 type is defined in two subgraphs, but field1 is flagged as @internal in one subgraph and field2 is flagged as @internal in the other subgraph, resulting in an empty merged input object type:

          -
          Counter Example № 47input Input1 {
          -  field1: String @internal
          -  field2: Int
          -}
          -
          -input Input1 {
          -  field1: String
          -  field2: Int @internal
          -}
          -
          -

          In the following example, the merged input object type Input1 is invalid. The type is defined in two subgraphs, but do not have the common field field1 is flagged as @internal in one of the subgraphs:

          -
          Counter Example № 48input Input1 {
          -  field1: String @internal
          -}
          -
          -input Input1 {
          -  field1: String
          -}
          -
          -
          -
          -
          -

          4.1.4.4Input Field Default Mismatch

          -
          -
          Error Code
          -

          F0011

          -
          -
          -
          Formal Specification
          -
            -
          • Let inputFieldsByName be a map where the key is the name of an input field and the value is a list of input fields from different subgraphs from the same type with the same name.
          • -
          • For each inputFields in inputFieldsByName:
              -
            • Let defaultValues be a set containing the default values of each input field in inputFields.
            • -
            • If the size of defaultValues is greater than -
            • -
            -
          • -
          -
          -InputFieldsHaveConsistentDefaults(inputFields)
            -
          1. Given each pair of input fields inputFieldA and inputFieldB in inputFields:
              -
            1. If the default value of inputFieldA is not equal to the default value of inputFieldB:
                -
              1. return false
              2. -
              -
            2. -
            -
          2. -
          3. return true
          4. -
          -
          -
          -
          -
          Explanatory Text
          -

          Input fields in different subgraphs that have the same name are required to have consistent default values. This ensures that there is no ambiguity or inconsistency when merging schemas from different subgraphs.

          -

          A mismatch in default values for input fields with the same name across different subgraphs will result in a schema composition error.

          -

          In the the following example both subgraphs have an input field field1 with the same default value. This is valid:

          -
          Example № 49input Filter {
          -  field1: Enum1 = Value1
          -}
          -
          -enum Enum1 {
          -  Value1
          -  Value2
          -}
          -
          -input Filter {
          -  field1: Enum1 = Value1
          -}
          -
          -enum Enum1 {
          -  Value1
          -  Value2
          -}
          -
          -

          In the following example both subgraphs define an input field field1 with different default values. This is invalid:

          -
          Counter Example № 50input Filter {
          -  field1: Int = 10
          -}
          -
          -input Filter {
          -  field1: Int = 20
          -}
          -
          -
          -
          -
          -

          4.1.4.5Public Input Fields Cannot Reference Internals

          -
          -
          Error Code
          -

          F0015

          -
          -
          -
          Formal Specification
          -
            -
          • Let subgraphs be a list of all subgraphs.
          • -
          • For each subgraph in subgraphs:
              -
            • Let fields be the set of all fields of the input types in subgraph
            • -
            • For each field in fields:
                -
              • If IsExposed(field) is true
                  -
                • Let namedType be the named type that field references
                • -
                • IsExposed(namedType) must be true
                • -
                -
              • -
              -
            • -
            -
          • -
          -
          -
          -
          Explanatory Text
          -

          In a composed schema, a field within a input type must only reference types that are exposed. This requirement guarantees that public types do not reference internal structures which are intended for internal use.

          -

          A valid case where a public input field references another public input type:

          -
          Example № 51input Input1 {
          -  field1: String!
          -  field2: Input2
          -}
          -
          -input Input2 {
          -  field3: String
          -}
          -
          -input Input1 {
          -  field1: String!
          -  field2: Input2
          -}
          -
          -input Input2 {
          -  field3: String
          -}
          -
          -

          Another valid case is where the field is not exposed in the composed schema:

          -
          Example № 52input Input1 {
          -  field1: String!
          -  field2: Input2
          -}
          -
          -input Input2 {
          -  field3: String
          -}
          -
          -input Input1 {
          -  field1: String!
          -  field4: Int
          -}
          -
          -

          An invalid case where a public input field in one subgraph references an input type that is marked as @internal in another subgraph:

          -
          Counter Example № 53input Input1 {
          -  field1: String!
          -  field2: Input2
          -}
          -
          -input Input2 {
          -  field3: String
          -}
          -
          -input Input1 {
          -  field1: String!
          -  field4: Int
          -}
          -
          -input Input2 @internal {
          -  field3: String
          -}
          -
          -
          -
          -
          -

          4.1.4.6Required Input Fields cannot be internal

          -
          -
          Error Code
          -

          F0012

          -
          -
          -
          Formal Specification
          -
            -
          • Let subgraphs be a list of all subgraphs.
          • -
          • For each subgraph in subgraphs:
              -
            • Let inputs be the set of all input object types in the subgraph
            • -
            • For each input in inputs:
                -
              • Let fields be a list of fields of input
              • -
              • For each field in fields:
                  -
                • If IsExposed(field) is false
                    -
                  • Let type be the type of field
                  • -
                  • type must not be nullable
                  • -
                  -
                • -
                -
              • -
              -
            • -
            -
          • -
          -
          -
          -
          Explanatory Text
          -

          Input object types can be defined in multiple subgraphs. Required fields in these input object types (i.e., fields that are non-nullable) must be exposed in the composed graph. A required internal field would create a contradiction where a field is both necessary for the operation in the composed schema but also not available for external use.

          -

          This example shows a valid scenario where the required field is not marked as @internal:

          -
          Example № 54input InputType1 {
          -  field1: String!
          -}
          -
          -input InputType1 {
          -  field1: String!
          -}
          -
          -

          Consider the following example where an input object type InputType1 includes a required field field1:

          -
          Counter Example № 55input InputType1 {
          -  field1: String!
          -}
          -
          -input InputType1 {
          -  field1: String! @internal
          -}
          -
          -

          In this counter-example, the field field1 is only defined in one subgraph, so will not be included in the composed schema. Therefor this field cannot be non-nullable:

          -
          Counter Example № 56input InputType1 {
          -  field1: String!
          -  field2: String!
          -}
          -
          -input InputType1 {
          -  field2: String!
          -}
          -
          -
          -
          -
          -
          -

          4.1.5Enum Types

          -
          -

          4.1.5.1Values Must Be The Same Across Subgraphs

          -
          -
          Error Code
          -

          F0003

          -
          -
          -
          Formal Specification
          -
            -
          • Let enumsByName be a map where the key is the name of an enum type, and the value is a list of all enum types from different subgraphs with that name.
          • -
          • For each listOfEnum in enumsByName: -
          • -
          -
          -EnumAremergeable(enums)
            -
          1. Let values be the set of all values of the first enum in enums
          2. -
          3. For each enum in enums
              -
            1. Let enumValues be the set of all values of enum
            2. -
            3. values must be equal to enumValues
            4. -
            -
          4. -
          -
          -
          -
          -
          Explanatory Text
          -

          This rule ensures that enum types with the same name across different subgraphs in a supergraph have identical sets of values. Enums, must be consistent across subgraphs to avoid conflicts and ambiguities in the composed schema.

          -

          When an enum is defined with differing values across subgraphs, it can lead to confusion and errors in query execution. For instance, a value valid in one subgraph might be passed to another where it’s unrecognized, leading to unexpected behavior or failures. This rule prevents such inconsistencies by enforcing that all instances of the same named enum across subgraphs have an exact match in their values.

          -

          In this example, both subgraphs define Enum1 with the same value BAR, satisfying the rule:

          -
          Example № 57enum Enum1 {
          -  BAR
          -}
          -
          -enum Enum1 {
          -  BAR
          -}
          -
          -

          Here, the two definitions of Enum1 have different values (BAR and Baz), violating the rule:

          -
          Counter Example № 58enum Enum1 {
          -  BAR
          -}
          -
          -enum Enum1 {
          -  Baz
          -}
          -
          -
          -
          -
          -

          4.1.5.2Default Value Uses Internals

          -
          -
          Error Code
          -

          F0008

          -
          -
          -
          Formal Specification
          - -
          -ValidateArgumentDefaultValues()
            -
          1. Let arguments be all arguments of fields and directives across all subgraphs
          2. -
          3. For each argument in arguments
              -
            1. If IsExposed(argument) is true and has a default value:
                -
              1. Let defaultValue be the default value of argument
              2. -
              3. If not ValidateDefaultValue(defaultValue)
                  -
                1. return false
                2. -
                -
              4. -
              -
            2. -
            -
          4. -
          5. return true
          6. -
          -
          -
          -ValidateInputFieldDefaultValues()
            -
          1. Let inputFields be all input fields of across all subgraphs
          2. -
          3. For each inputField in inputFields:
              -
            1. Let type be the type of inputField
            2. -
            3. If IsExposed(inputField) is true and inputField has a default value:
                -
              1. Let defaultValue be the default value of inputField
              2. -
              3. if ValidateDefaultValue(defaultValue) is false
                  -
                1. return false
                2. -
                -
              4. -
              -
            4. -
            -
          4. -
          5. return true
          6. -
          -
          -
          -ValidateDefaultValue(defaultValue)
            -
          1. If defaultValue is a ListValue:
              -
            1. For each valueNode in defaultValue:
                -
              1. If ValidateDefaultValue(valueNode) is false
                  -
                1. return false
                2. -
                -
              2. -
              -
            2. -
            -
          2. -
          3. If defaultValue is an ObjectValue:
              -
            1. Let objectFields be a list of all fields of defaultValue
            2. -
            3. Let fields be a list of all fields objectFields are referring to
            4. -
            5. For each field in fields:
                -
              1. If IsExposed(field) is false
                  -
                1. return false
                2. -
                -
              2. -
              -
            6. -
            7. For each objectField in objectFields:
                -
              1. Let value be the value of objectField
              2. -
              3. return ValidateDefaultValue(value)
              4. -
              -
            8. -
            -
          4. -
          5. If defaultValue is an EnumValue:
              -
            1. If IsExposed(defaultValue) is false
                -
              1. return false
              2. -
              -
            2. -
            -
          6. -
          7. return true
          8. -
          -
          -
          -
          -
          Explanatory Text
          -

          A default value for an argument in a field must only reference enum values or a input fields that are exposed in the composed schema. This rule ensures that internal members are not exposed in the composed schema through default values.

          -

          In this example the FOO value in the Enum1 enum is not marked with @internal, hence it doesn’t violate the rule.

          -
          type Query {
          -  field(type: Enum1 = FOO): [Baz!]!
          -}
          -
          -enum Enum1 {
          -  FOO
          -  BAR
          -}
          -
          -

          This example is a violation of the rule because the default value for the field field in type Input1 references an enum value (FOO) that is marked as @internal.

          -
          Counter Example № 59type Query {
          -  field(type: Input1): [Baz!]!
          -}
          -
          -input Input1 {
          -  field: Enum1 = FOO
          -}
          -
          -enum Enum1 {
          -  FOO @internal
          -  BAR
          -}
          -
          -
          Counter Example № 60type Query {
          -  field(type: Input1 = { field2: "ERROR" }): [Baz!]!
          -}
          -
          -input Input1 {
          -  field1: String
          -  field2: String @internal
          -}
          -
          -

          This example is a violation of the rule because the default value for the type argument in the field field references an enum value (BAR) that is marked as @internal.

          -

          graphql example counter-example type Query { field(type: Enum1 = BAR): [Baz!]! } enum Enum1 { FOO BAR @internal }

          -
          -
          -
          -

          4.1.5.3Empty Merged Enum Type

          -
          -
          Error Code
          -

          F0009

          -
          -
          -
          Formal Specification
          -
            -
          • Let enumsByName be the set of all enums across all subgraphs involved in the schema composition grouped by their name.
          • -
          • For each enum in enumsByName: -
          • -
          -
          -IsEnumEmpty(enum)
            -
          1. Let values be a set of enum values for enum across all subgraphs
          2. -
          3. For each value in values
              -
            1. If IsExposed(value) is true
                -
              1. return false
              2. -
              -
            2. -
            -
          4. -
          5. return true
          6. -
          -
          -
          -
          -
          Explanatory Text
          -

          If an enum type is defined in multiple subgraphs, only values not flagged as @internal in all subgraphs are included in the merged enum type. If this process results in an enum type with no values, the enum type is considered empty and invalid.

          -

          The following example shows a valid merged enum type. The Enum1 type is defined in two subgraphs:

          -
          enum Enum1 {
          -  Value1 @internal
          -  Value2
          -}
          -
          -enum Enum1 {
          -  Value1
          -  Value2
          -}
          -
          -

          This counter-example shows an invalid merged enum type. The Enum1 type is defined in two subgraphs, but the Value1 and Value2 values are flagged as @internal in one of the subgraphs:

          -
          Counter Example № 61enum Enum1 {
          -  Value1 @internal
          -  Value2 @internal
          -}
          -
          -enum Enum1 {
          -  Value1
          -  Value2
          -}
          -
          -

          In this counter-example, the Enum1 type is defined in two subgraphs, but the Value1 value is flagged as @internal in one of the subgraphs and the Value2 value is flagged as @internal in the other subgraph which results in an empty merged enum type:

          -
          Counter Example № 62enum Enum1 {
          -  Value1 @internal
          -  Value2
          -}
          -
          -enum Enum1 {
          -  Value1
          -  Value2 @internal
          -}
          -
          -
          -
          -
          -
          -

          4.1.6Interface

          -
          -

          4.1.6.1Empty Merged Interface Type

          -
          -
          Error Code
          -

          F0018

          -
          -
          -
          Formal Specification
          -
            -
          • Let interfaces be the set of all interface types across all subgraphs.
          • -
          • For each interface in interfaces: -
          • -
          -
          -IsInterfaceTypeEmpty(interface)
            -
          1. Let fields be a set of all fields across all subgraphs with coordinate and kind of interface
          2. -
          3. For each field in fields:
              -
            1. If IsExposed(field) is true
                -
              1. return false
              2. -
              -
            2. -
            -
          4. -
          5. return true
          6. -
          -
          -
          -
          -
          Explanatory Text
          -

          When an interface type is defined in multiple subgraphs, only common fields and fields not flagged as @internal are included in the merged interface type. If this process results in an interface type with no fields, the interface type is considered empty and invalid.

          -

          In the following example, the merged interface type Interface1 is valid. The type is defined in two subgraphs:

          -
          Example № 63interface Interface1 {
          -  field1: String @internal
          -  field2: Int
          -}
          -
          -interface Interface1 {
          -  field1: String
          -  field2: Int
          -}
          -
          -

          In the following example, the merged interface type Interface1 is valid and contains field1 as it exists in both subgraphs. The type is defined in two subgraphs:

          -
          Example № 64interface Interface1 {
          -  field1: String
          -}
          -
          -interface Interface1 {
          -  field1: String
          -  field2: Int
          -}
          -
          -

          In the following example, the merged interface type Interface1 is invalid. The type is defined in two subgraphs, but do not have any common fields:

          -
          Counter Example № 65interface Interface1 {
          -  field1: String
          -}
          -
          -interface Interface1 {
          -  field2: String
          -}
          -
          -

          This counter-example shows an invalid merged interface type. The Interface1 type is defined in two subgraphs, but both field1 and field2 are flagged as @internal in one of the subgraphs:

          -
          Counter Example № 66interface Interface1 {
          -  field1: String @internal
          -  field2: Int @internal
          -}
          -
          -interface Interface1 {
          -  field1: String
          -  field2: Int
          -}
          -
          -

          In this counter-example, the Interface1 type is defined in two subgraphs, but field1 is flagged as @internal in one subgraph and field2 is flagged as @internal in the other subgraph, resulting in an empty merged interface type:

          -
          Counter Example № 67interface Interface1 {
          -  field1: String @internal
          -  field2: Int
          -}
          -
          -interface Interface1 {
          -  field1: String
          -  field2: Int @internal
          -}
          -
          -

          In the following example, the merged interface type Interface1 is invalid. The type is defined in two subgraphs, but the common field field1 is flagged as @internal in one of the subgraphs:

          -
          Counter Example № 68interface Interface1 {
          -  field1: String @internal
          -}
          -
          -interface Interface1 {
          -  field1: String
          -}
          -
          -
          -
          -
          -
          -

          4.1.7Union

          -
          -

          4.1.7.1Union Type Members Cannot Reference Internals

          -
          -
          Error Code
          -

          F0017

          -
          -
          -
          Formal Specification
          -
            -
          • Let subgraphs be a list of all subgraphs.
          • -
          • For each subgraph in subgraphs:
              -
            • Let unionTypes be the set of all union types in subgraph.
            • -
            • For each unionType in unionTypes:
                -
              • Let members be the set of member types of unionType
              • -
              • For each member in members:
                  -
                • Let type be the type of member
                • -
                • IsExposed(type) must be true
                • -
                -
              • -
              -
            • -
            -
          • -
          -
          -
          -
          Explanatory Text
          -

          A union type must not include members where the type is marked as @internal in any subgraph. This rule ensures that the composed schema does not expose internal types.

          -

          Here is a valid example where all member types of a union are public:

          -
          Example № 69type Object1 {
          -  field1: String
          -}
          -
          -type Object2 {
          -  field2: Int
          -}
          -
          -union Union1 = Object1 | Object2
          -
          -type Object3 {
          -  field3: Boolean
          -}
          -
          -union Union1 = Object3
          -
          -

          In this counter-example, the member type Object2 is marked as @internal in the second subgraph, so the composed schema is invalid:

          -
          Counter Example № 70union Union1 = Object1 | Object2
          -
          -type Object1 {
          -  field1: String
          -}
          -
          -type Object2 {
          -  field2: Int
          -}
          -
          -union Union1 = Object1 | Object2
          -
          -type Object1 {
          -  field1: String
          -}
          -
          -type Object2 @internal {
          -  field2: Int
          -  field4: Float
          -}
          -
          -
          -
          -
          -
          -

          4.1.8Schema

          -
          -

          4.1.8.1No Queries

          -
          -
          Error Code
          -

          F0007

          -
          -
          -
          Formal Specification
          -
            -
          • Let schemas be the set of all subgraph schemas involved in the composition
          • -
          • HasQueryRootType(schemas) must be true
          • -
          -
          -HasQueryRootType(schemas)
            -
          1. for each schema in schemas
              -
            1. let queryRootType be the query root type of schema
            2. -
            3. let fields be the fields of queryRootType
            4. -
            5. if fields is not empty
                -
              1. return true
              2. -
              -
            6. -
            -
          2. -
          3. return false
          4. -
          -
          -
          -
          -
          Explanatory Text
          -

          A schema composed from multiple subgraphs must have a query root type to be valid. The query root type is essential. This rule ensures that at least one subgraph in the composition defines a query root type that defines at least one query field.

          -

          The examples provided in the test cases demonstrate how the absence or presence of a valid query root type impacts the composition result. A composition that does not meet this requirement should result in an error with the code F0007, indicating the need for at least one query field across the included subgraphs.

          -
          type Query {
          -  field1: String
          -}
          -
          -type Query {
          -  field2: String @remove
          -}
          -
          -

          In the example, both field1 and field2 are marked for removal, leaving no valid query fields:

          -
          Counter Example № 71type Query {
          -  field1: String @remove
          -}
          -
          -type Query @remove {
          -  field2: String
          -}
          -
          -

          In this case, the presence of @internal on field1 removes the field from the composed schema, leaving no accessible query fields.

          -
          Counter Example № 72type Query {
          -  field1: String @internal
          -}
          -
          -type Query {
          -  field1: String
          -}
          -
          -
          -
          -
          -
          -

          4.1.9Shared Functions

          -
          -

          4.1.9.1Same Type Shape

          -

          If types differ only in nullability they are still considered mergeable. This algorithm determines if two types are mergeable by removing non-nullability from the types when comparing them.

          -
          -SameTypeShape(typeA, typeB)
            -
          1. If typeA is Non-Null:
              -
            1. If typeB is nullable
                -
              1. Let innerType be the inner type of typeA.
              2. -
              3. return SameTypeShape(innerType, typeB).
              4. -
              -
            2. -
            -
          2. -
          3. If typeB is Non-Null:
              -
            1. If typeA is nullable
                -
              1. Let innerType be the inner type of typeB.
              2. -
              3. return SameTypeShape(typeA, innerType).
              4. -
              -
            2. -
            -
          4. -
          5. If typeA or typeB is List:
              -
            1. If typeA or typeB is not List
                -
              1. return false.
              2. -
              -
            2. -
            3. Let innerTypeA be the item type of typeA.
            4. -
            5. Let innerTypeB be the item type of typeB.
            6. -
            7. return SameTypeShape(innerTypeA, innerTypeB).
            8. -
            -
          6. -
          7. If typeA and typeB are not of the same kind
              -
            1. return false.
            2. -
            -
          8. -
          9. If typeA and typeB do not have the same name
              -
            1. return false.
            2. -
            -
          10. -
          -
          -
          -
          -

          4.1.9.2Is Exposed

          -
          -IsExposed(member)
            -
          1. Let members be a list of all members across all subgraphs with the same coordinate and kind as member
          2. -
          3. If any members is marked with @internal
              -
            1. return false
            2. -
            -
          4. -
          5. If member is InputField
              -
            1. Let type be any input object type that member is declared on
            2. -
            3. if IsExposed(type) is false
                -
              1. return false
              2. -
              -
            4. -
            5. Let types be the list of all types across all subgraphs with the same coordinate and kind as type
            6. -
            7. If member is in CommonFields(types)
                -
              1. return true
              2. -
              -
            8. -
            9. return false
            10. -
            -
          6. -
          7. If member is EnumValue
              -
            1. Let enum be any enum that member is declared on
            2. -
            3. return IsExposed(enum)
            4. -
            -
          8. -
          9. If member is ObjectField
              -
            1. Let type be the any type that member is declared on
            2. -
            3. return IsExposed(type)
            4. -
            -
          10. -
          11. If member is InterfaceField
              -
            1. Let type be the any type that member is declared on
            2. -
            3. If IsExposed(type) is false
                -
              1. return false
              2. -
              -
            4. -
            5. Let types be the list of all types across all subgraphs with the same coordinate and kind as type
            6. -
            7. If member is in CommonFields(types)
                -
              1. return true
              2. -
              -
            8. -
            9. return false
            10. -
            -
          12. -
          13. If member is Argument
              -
            1. If member is declared on a field:
                -
              1. Let declaringField be any field that member is declared on
              2. -
              3. If IsExposed(declaringField) is false
                  -
                1. return false
                2. -
                -
              4. -
              5. Let declaringFields be the list of all fields across all subgraphs with the same coordinate and kind as declaringField
              6. -
              7. If member is in CommonArguments(declaringFields)
                  -
                1. return true
                2. -
                -
              8. -
              9. return false
              10. -
              -
            2. -
            3. If member is declared on a directive
                -
              1. Let declaringDirective be any directive that member is declared on
              2. -
              3. If IsExposed(declaringDirective) is false
                  -
                1. return false
                2. -
                -
              4. -
              5. Let declaringDirectives be the list of any directives across all subgraphs with the same coordinate and kind as declaringDirective
              6. -
              7. If member is in CommonArguments(declaringDirectives)
                  -
                1. return true
                2. -
                -
              8. -
              9. return false
              10. -
              -
            4. -
            -
          14. -
          15. return true
          16. -
          -
          -
          -CommonArguments(members)
            -
          1. Let commonArguments be the set of all arguments of all members across all subgraphs
          2. -
          3. For each member in members
              -
            1. Let arguments be the set of all arguments of member
            2. -
            3. Let commonArguments be the intersection of commonArguments and arguments
            4. -
            -
          4. -
          5. return commonArguments
          6. -
          -
          -
          -CommonFields(members)
            -
          1. Let commonFields be the set of all fields of all members across all subgraphs
          2. -
          3. For each member in members
              -
            1. Let fields be the set of all fields of member
            2. -
            3. Let commonFields be the intersection of commonFields and fields
            4. -
            -
          4. -
          5. return commonFields
          6. -
          -
          -
          -
          -
          -
          -

          4.2Compose

          -

          To compose a gateway configuration the composition tooling must have loaded at least one subgraph configuration.

          -
          -ComposeConfiguration(subgraphConfigurations)
            -
          1. For each subgraphConfiguration in subgraphConfigurations:
          2. -
          3. Let subgraphSchema be the result of BuildSubgraphSchema(subgraphConfiguration).
          4. -
          -
          -
          -BuildSubgraphSchema(subgraphConfiguration)
            -
          1. Todo
          2. -
          -
          -
          -MergeType(typesOrTypeExtensions)
            -
          1. Todo
          2. -
          -
          -
          -MergeSchema(schemaA, schemaB)
            -
          1. Let mergedSchema be an empty SchemaDefinition
          2. -
          3. Let queryTypeA be the query type of schemaA
          4. -
          5. Set mergedSchema to have query type queryTypeA
          6. -
          7. Let mutationTypeA be the mutation type of schemaA or null
          8. -
          9. Let mutationTypeB be the mutation type of schemaB or null
          10. -
          11. If mutationTypeA is not null
              -
            1. Set mergedSchema to have mutation type mutationTypeA
            2. -
            -
          12. -
          13. If mutationTypeA is null and mutationTypeB is not null
              -
            1. Set mergedSchema to have mutation type mutationTypeB
            2. -
            -
          14. -
          15. Let subscriptionTypeA be the subscription type of schemaA or null
          16. -
          17. Let subscriptionTypeB be the subscription type of schemaB or null
          18. -
          19. If subscriptionTypeA is not null
              -
            1. Set mergedSchema to have subscription type subscriptionTypeA
            2. -
            -
          20. -
          21. If subscriptionTypeA is null and subscriptionTypeB is not null
              -
            1. Set mergedSchema to have subscription type subscriptionTypeB
            2. -
            -
          22. -
          23. return mergedSchema
          24. -
          -
          -
          -

          4.2.1MergeObjectType

          -

          This algorithm combines two object types from different subgraphs into a single object type. It does this only if neither type is marked as @internal, ensuring internal types remain private.

          -

          This algorithm creates a merged output type containing all the fields from both types, unless they are marked as @internal. When the same field exists in both types, it merges these fields into one.

          -

          The fields are merged by name, and the merged field is the result of calling MergeOutputField(fieldA, fieldB).

          -
          -MergeOutputType(typeA, typeB)
            -
          1. If typeA or typeB are @internal
              -
            1. return null
            2. -
            -
          2. -
          3. Let outputType be an empty OutputObjectTypeDefinition
          4. -
          5. Let fields be a set of field names that are defined on either typeA or typeB
          6. -
          7. For each fieldName in fields:
              -
            1. Let fieldA be the field with the same name on typeA
            2. -
            3. Let fieldB be the field with the same name on typeB
            4. -
            5. If fieldA or fieldB are @internal
                -
              1. continue
              2. -
              -
            6. -
            7. If fieldB is null
                -
              1. Append fieldA to outputType
              2. -
              3. continue
              4. -
              -
            8. -
            9. If fieldA is null
                -
              1. Append fieldB to outputType
              2. -
              3. continue
              4. -
              -
            10. -
            11. Let mergedField be the result of calling MergeOutputField(fieldA, fieldB)
            12. -
            13. Append mergedField to outputType
            14. -
            -
          8. -
          9. Set outputType to have the same name as typeA
          10. -
          11. Set outputType to have MergeInterfaceImplementation(typeA, typeB) as its interfaces
          12. -
          13. return outputType
          14. -
          -
          -

          Examples of Merging Output Object Types:

          -
          Example № 73# Subgraph A
          -type OutputTypeA {
          -  commonField: String
          -  uniqueFieldA: Int
          -}
          -
          -# Subgraph B
          -type OutputTypeA {
          -  commonField: String
          -  uniqueFieldB: Boolean
          -}
          -
          -# Result
          -type OutputTypeA {
          -  commonField: String
          -  uniqueFieldA: Int
          -  uniqueFieldB: Boolean
          -}
          -
          -

          Merging Output Object Types with @internal Fields:

          -
          Example № 74# Subgraph A
          -type OutputTypeA {
          -  commonField: String
          -  internalField: Int @internal
          -}
          -
          -# Subgraph B
          -type OutputTypeA {
          -  commonField: String
          -  uniqueFieldB: Boolean
          -}
          -
          -# Result
          -type OutputTypeA {
          -  commonField: String
          -  uniqueFieldB: Boolean
          -}
          -
          -
          -
          -

          4.2.2MergeInputType

          -

          This algorithm merges two input object types from different subgraphs. It excludes any type marked with @internal, ensuring internal types are not exposed in the merged schema.

          -

          The fields of the merged input object type are the intersection of the fields of the input object types from the subgraphs. This approach ensures that the merged input object type is compatible with both subgraphs.

          -

          The fields are merged by name, and the merged field is the result of calling MergeInputField(fieldA, fieldB).

          -
          -MergeInputType(typeA, typeB)
            -
          1. If typeA or typeB are @internal
              -
            1. return null
            2. -
            -
          2. -
          3. Let inputType be an empty InputObjectTypeDefinition
          4. -
          5. Let commonFields be the set of fields names that are defined on both typeA and typeB
          6. -
          7. For each field in commonFields:
              -
            1. Let fieldA be the field with the same name on typeA
            2. -
            3. Let fieldB be the field with the same name on typeB
            4. -
            5. If fieldA or fieldB are @internal
                -
              1. continue
              2. -
              -
            6. -
            7. Let mergedField be the result of calling MergeInputField(fieldA, fieldB)
            8. -
            9. Append mergedField to inputType
            10. -
            -
          8. -
          9. Set inputType to have the same name as typeA
          10. -
          11. return inputType
          12. -
          -
          -

          Merging Common Input Object Fields:

          -
          Example № 75# Subgraph A
          -input InputTypeA {
          -  commonField: String
          -  uniqueFieldA: Int
          -}
          -
          -# Subgraph B
          -input InputTypeA {
          -  commonField: String
          -  uniqueFieldB: Boolean
          -}
          -
          -# Merged Input Object
          -input InputTypeA {
          -  commonField: String
          -}
          -
          -

          Merging Common Input Object Fields with @internal Fields:

          -
          Example № 76# Subgraph A
          -input InputTypeA {
          -  commonField: String
          -  internalField: Int @internal
          -}
          -
          -# Subgraph B
          -input InputTypeA {
          -  commonField: String
          -  internalField: Int
          -}
          -
          -# Merged Input Object
          -input InputTypeA {
          -  commonField: String
          -}
          -
          -
          -
          -

          4.2.3MergeInterfaceType

          -

          This algorithm merges two interface types from different subgraphs, given that neither type is marked as @internal.

          -

          The resulting interface type is the intersection of the fields of the interface types from the subgraphs. This approach ensures that the merged interface type is compatible with object types from both subgraphs.

          -

          The fields are merged by name, and the merged field is the result of calling MergeOutputField(fieldA, fieldB).

          -
          -MergeInterfaceType(typeA, typeB)
            -
          1. If typeA or typeB are @internal
              -
            1. return null
            2. -
            -
          2. -
          3. Let interfaceType be an empty InterfaceTypeDefinition
          4. -
          5. Let fields be a set of common field names that are defined in typeA and typeB
          6. -
          7. For each fieldName in fields:
              -
            1. Let fieldA be the field with the same name on typeA
            2. -
            3. Let fieldB be the field with the same name on typeB
            4. -
            5. If fieldA or fieldB are @internal
                -
              1. continue
              2. -
              -
            6. -
            7. Let mergedField be the result of calling MergeOutputField(fieldA, fieldB)
            8. -
            9. Append mergedField to interfaceType
            10. -
            -
          8. -
          9. Set interfaceType to have the same name as typeA
          10. -
          11. Set interfaceType to have MergeInterfaceImplementation(typeA, typeB) as its interfaces
          12. -
          13. return interfaceType
          14. -
          -
          -

          Merging Common Fields:

          -
          Example № 77# Subgraph A
          -interface InterfaceA {
          -  commonField: String
          -}
          -
          -# Subgraph B
          -interface InterfaceA {
          -  commonField: String
          -  uniqueField: Boolean
          -}
          -
          -# Merged Interface
          -interface InterfaceA {
          -  commonField: String
          -}
          -
          -

          Merging Common Fields with @internal Fields:

          -
          Example № 78# Subgraph A
          -interface InterfaceA {
          -  commonField: String
          -  internalField: Int @internal
          -}
          -
          -# Subgraph B
          -interface InterfaceA {
          -  commonField: String
          -  internalField: Int
          -}
          -
          -# Merged Interface
          -interface InterfaceA {
          -  commonField: String
          -}
          -
          -

          This counter example shows why it is important that the gateway uses the intersection rather than the union of the fields of the interface types from the subgraphs:

          -
          Counter Example № 79# Subgraph A
          -interface InterfaceA {
          -  commonField: String
          -  uniqueFieldA: Int
          -}
          -
          -type ObjectA implements InterfaceA {
          -  commonField: String
          -  uniqueFieldA: Int
          -}
          -
          -# Subgraph B
          -interface InterfaceA {
          -  commonField: String
          -  uniqueFieldB: Boolean
          -}
          -
          -# Merged Interface
          -
          -interface InterfaceA {
          -  commonField: String
          -  uniqueFieldA: Int
          -  uniqueFieldB: Boolean
          -}
          -
          -# This object type is no longer compatible with the merged interface types as it is
          -# missing the `uniqueFieldB` field.
          -type ObjectA implements InterfaceA {
          -  commonField: String
          -  uniqueFieldA: Int
          -}
          -
          -
          -
          -

          4.2.4MergeUnionType

          -

          This algorithm is used to merge two union types from separate subgraphs. It combines the members from both union types into a new union type by name, given neither original type is marked as @internal.

          -

          This algorithm has to combine the members of both types, because otherwise there is the possibility of invalid states during the execution. If members were removed from the union type, the subgraph could still return it as a result of a query, which would be invalid in the composed schema.

          -
          -MergeUnionType(typeA, typeB)
            -
          1. If typeA or typeB are @internal
              -
            1. return null
            2. -
            -
          2. -
          3. Let unionType be an empty UnionTypeDefinition
          4. -
          5. Let types be a set of type names that are defined on either typeA or typeB
          6. -
          7. Set unionType to have the same name as typeA
          8. -
          9. Set types to be the types of unionType
          10. -
          11. return unionType
          12. -
          -
          -

          Merging Union Types:

          -
          # Subgraph A
          -union UnionTypeA = Type1 | Type2
          -
          -# Subgraph B
          -union UnionTypeA = Type2 | Type3
          -
          -# Result
          -union UnionTypeA = Type1 | Type2 | Type3
          -
          -

          Merging Union Types with @internal:

          -
          # Subgraph A
          -union UnionTypeA = Type1 | Type2
          -
          -# Subgraph B
          -union UnionTypeA @internal = Type2 | Type3
          -
          -# Result
          -null
          -
          -

          The following counter-example shows a invalid composition. Subgraph A could still return Type1 for the field field1, which would lead to an execution error:

          -
          Counter Example № 80# Subgraph A
          -union UnionTypeA = Type1 | Type2
          -
          -type Type1 {
          -  field1: UnionTypeA
          -}
          -
          -# Subgraph B
          -union UnionTypeA = Type2
          -
          -type Type1 {
          -  field1: UnionTypeA
          -}
          -
          -# Result
          -union UnionTypeA = Type2
          -
          -type Type1 {
          -  field1: UnionTypeA
          -}
          -
          -
          -
          -

          4.2.5MergeEnumType

          -

          This algorithm merges two enum types from different subgraphs into one, given if neither is marked as @internal. This process simply retains the enum values from typeA for the merged enum type as typeA and typeB are guaranteed to have the same values because Values Must Be The Same Across Subgraphs

          -

          Since enum types can be used both as input and output types, they must be strictly equal in both subgraphs. This strict equality rule avoids any invalid states that could arise from using either an intersection or union of the enum values.

          -
          -MergeEnumType(typeA, typeB)
            -
          1. If typeA or typeB are @internal
              -
            1. return null
            2. -
            -
          2. -
          3. Let enumType be an empty EnumTypeDefinition
          4. -
          5. Let valuesOfA be the set of enum values defined on typeA
          6. -
          7. Set enumType to have the same name as typeA
          8. -
          9. Set valuesOfA to be the values of enumType
          10. -
          11. return enumType
          12. -
          -
          -

          Examples of Merging Enum Types:

          -
          # Subgraph A
          -enum EnumTypeA {
          -  VALUE1
          -  VALUE2
          -}
          -
          -# Subgraph B
          -enum EnumTypeA {
          -  VALUE1
          -  VALUE2
          -}
          -
          -# Result
          -enum EnumTypeA {
          -  VALUE1
          -  VALUE2
          -}
          -
          -

          The following counter-example shows an invalid composition that uses the union merge approach. A query to subgraph B could use VALUE1 in field1 which would lead to an execution error:

          -
          Counter Example № 81# Subgraph A
          -enum EnumType1 {
          -  VALUE1
          -}
          -
          -# Subgraph B
          -enum EnumType1 {
          -  VALUE2
          -}
          -
          -input Input1 {
          -  field1: EnumType1
          -}
          -
          -# Result
          -enum EnumType1 {
          -  VALUE1
          -  VALUE2
          -}
          -
          -input Input1 {
          -  field1: EnumType1
          -}
          -
          -

          The following counter-example shows an invalid composition that uses the intersection merge approach. A query to subgraph A could return VALUE2 in field1 which would lead to an execution error:

          -
          Counter Example № 82# Subgraph A
          -enum EnumType1 {
          -  VALUE1
          -}
          -
          -type Type1 {
          -  field1: EnumType1
          -}
          -
          -# Subgraph B
          -enum EnumType1 {
          -  VALUE2
          -}
          -
          -# Result
          -enum EnumType1 {
          -  VALUE1
          -  VALUE2
          -}
          -
          -input Type1 {
          -  field1: EnumType1
          -}
          -
          -
          -
          -

          4.2.6MergeInputField

          -

          This algorithm merges two input fields from the same type of different subgraphs into one. The algorithm expects that both fields have the same schema coordinate. The type of the field is the result of calling MergeInputFieldType(typeA, typeB).

          -
          -MergeInputField(fieldA, fieldB)
            -
          1. Let mergedField be an empty InputFieldDefinition
          2. -
          3. Let typeA be the type of fieldA
          4. -
          5. Let typeB be the type of fieldB
          6. -
          7. Let mergedType be the result of calling MergeInputFieldType(typeA, typeB)
          8. -
          9. Set mergedField to have the same name as fieldA
          10. -
          11. Set mergedField to have mergedType as its type
          12. -
          13. return mergedField
          14. -
          -
          -

          Merging Input Fields:

          -
          Example № 83# Subgraph A
          -input InputTypeA {
          -  field1: String
          -}
          -
          -# Subgraph B
          -input InputTypeA {
          -  field1: String!
          -}
          -
          -# Result
          -input InputTypeA {
          -  field1: String!
          -}
          -
          -
          -
          -

          4.2.7MergeOutputField

          -

          This algorithm merges two output fields from the same type of different subgraphs into one. The algorithm expects that both fields have the same schema coordinate. The arguments of both fields are merged based on MergeArguments(fieldA, fieldB). The type of the field is the result of calling MergeOutputFieldType(typeA, typeB).

          -
          -MergeOutputField(fieldA, fieldB)
            -
          1. Let mergedField be an empty OutputFieldDefinition
          2. -
          3. Let typeA be the type of fieldA
          4. -
          5. Let typeB be the type of fieldB
          6. -
          7. Let mergedType be the result of calling MergeOutputFieldType(typeA, typeB)
          8. -
          9. Set mergedField to have the same name as fieldA
          10. -
          11. Set mergedField to have mergedType as its type
          12. -
          13. Set mergedField to have arguments MergeArguments(fieldA, fieldB)
          14. -
          15. return mergedField
          16. -
          -
          -

          Merging Output Fields:

          -
          Example № 84# Subgraph A
          -type OutputTypeA {
          -  field1(arg1: String, arg2: String): String
          -}
          -
          -# Subgraph B
          -type OutputTypeA {
          -  field1(arg1: String, arg3: String): String!
          -}
          -
          -# Result
          -type OutputTypeA {
          -  field1(arg1: String): String!
          -}
          -
          -
          -
          -

          4.2.8MergeArguments

          -

          This algorithm merges the arguments of two fields from the same type of different subgraphs into a combined list of arguments. The algorithm expects that both fields have the same schema coordinate.

          -

          The arguments are merged by name, and the merged argument is the result of calling MergeArgument(argumentA, argumentB).

          -

          Only arguments that are defined on both fields are merged. If an argument is only defined on one field, it is not included in the merged list to ensure that the merged field is compatible with both subgraphs.

          -
          -MergeArguments(fieldA, fieldB)
            -
          1. Let mergedArguments be an empty list of ArgumentDefinitions
          2. -
          3. Let arguments be the intersection of the set of argument names that are defined on fieldA and fieldB
          4. -
          5. For each argumentName in arguments:
              -
            1. Let argumentA be the argument with the same name on fieldA
            2. -
            3. Let argumentB be the argument with the same name on fieldB
            4. -
            5. If argumentA or argumentB are @internal
                -
              1. continue
              2. -
              -
            6. -
            7. Let mergedArgument be the result of calling MergeArgument(argumentA, argumentB)
            8. -
            9. Append mergedArgument to mergedArguments
            10. -
            -
          6. -
          7. return mergedArguments
          8. -
          -
          -

          Merging Arguments:

          -
          Example № 85# Subgraph A
          -type Type1 {
          -  field1(arg1: String, arg2: String): String
          -}
          -
          -# Subgraph B
          -type Type1 {
          -  field1(arg1: String, arg3: String): String
          -}
          -
          -# Result
          -type Type1 {
          -  field1(arg1: String): String
          -}
          -
          -

          The following counter-example shows an invalid composition. The field1 can be queried on the gateway with the argument arg2, which would lead to an execution error on subgraph B:

          -
          Counter Example № 86# Subgraph A
          -type Type1 {
          -  field1(arg1: String, arg2: String): String
          -}
          -
          -# Subgraph B
          -type Type1 {
          -  field1(arg1: String): String
          -}
          -
          -# Result
          -type Type1 {
          -  field1(arg1: String, arg2: String): String
          -}
          -
          -
          -
          -

          4.2.9MergeArgument

          -

          This algorithm merges two arguments from the same field of different subgraphs into one. The algorithm expects that both arguments have the same schema coordinate.

          -

          The type of the argument is the result of calling MergeInputFieldType(typeA, typeB).

          -
          -MergeArgument(argumentA, argumentB)
            -
          1. Let mergedArgument be an empty ArgumentDefinition
          2. -
          3. Let typeA be the type of argumentA
          4. -
          5. Let typeB be the type of argumentB
          6. -
          7. Let mergedType be the result of calling MergeInputFieldType(typeA, typeB)
          8. -
          9. Set mergedArgument to have the same name as argumentA
          10. -
          11. Set mergedArgument to have mergedType as its type
          12. -
          13. return mergedArgument
          14. -
          -
          -

          Merging Arguments:

          -
          Example № 87# Subgraph A
          -type Type1 {
          -  field1(arg1: String!): String
          -}
          -
          -# Subgraph B
          -type Type1 {
          -  field1(arg1: String): String
          -}
          -
          -# Result
          -type Type1 {
          -  field1(arg1: String!): String
          -}
          -
          -
          -
          -

          4.2.10MergeInterfaceImplementation

          -

          This algorithm merges the interfaces implemented by two types from different subgraphs into a combined list of interfaces. The algorithm ignores any interface that is marked as @internal, to avoid exposing a implementation that does not match a interface type.

          -
          -MergeInterfaceImplementation(typeA, typeB)
            -
          1. Let interfaceNames be the set of interface names that are defined on either typeA or typeB
          2. -
          3. Let validInterfaceNames be the set of all interface in the composition that are not @internal
          4. -
          5. Return the intersection of interfaceNames and validInterfaceNames
          6. -
          -
          -

          Merging Interface Implementations:

          -
          Example № 88# Subgraph A
          -interface Interface1 {
          -  field1: String
          -}
          -
          -type Type1 implements Interface1 {
          -  field1: String
          -}
          -
          -# Subgraph B
          -type Type1 {
          -  field1: String
          -}
          -
          -# Result
          -interface Interface1 {
          -  field1: String
          -}
          -
          -type Type1 implements Interface1 {
          -  field1: String
          -}
          -
          -

          Merging Interface Implementations with @internal Interfaces:

          -
          Example № 89# Subgraph A
          -interface Interface1 @internal {
          -  field1: String
          -}
          -
          -type Type1 implements Interface1 {
          -  field1: String
          -}
          -
          -# Subgraph B
          -type Type1 {
          -  field1: String
          -}
          -
          -# Result
          -type Type1 {
          -  field1: String
          -}
          -
          -

          The following counter-example shows an invalid composition. The Type1 type implements the Interface1 interface, but the Interface1 interface is marked as @internal in subgraph A.

          -
          Counter Example № 90# Subgraph A
          -interface Interface1 @internal {
          -  field1: String
          -}
          -
          -type Type1 implements Interface1 {
          -  field1: String
          -}
          -
          -# Subgraph B
          -type Type1 {
          -  field1: String
          -}
          -
          -
          -
          -

          4.2.11MergeInputFieldType

          -

          This algorithm merges two input types. The merge will result in the least permissive type, while still be compatible with both input types.

          -
          -MergeInputFieldType(typeA, typeB)
            -
          1. If typeA and typeB are the same
              -
            1. return typeA
            2. -
            -
          2. -
          3. If typeA is Non-Null and typeB is Non-Null
              -
            1. Let innerTypeA be the inner type of typeA
            2. -
            3. Let innerTypeB be the inner type of typeB
            4. -
            5. Let innerType be MergeOutputFieldType(innerTypeA, innerTypeB)
            6. -
            7. return EnsureNonNullType(innerType)
            8. -
            -
          4. -
          5. If typeA is Non-Null and typeB is nullable
              -
            1. Let innerTypeA be the inner type of typeA
            2. -
            3. Let mergedType be MergeOutputFieldType(innerTypeA, typeB)
            4. -
            5. return EnsureNonNullType(mergedType)
            6. -
            -
          6. -
          7. If typeB is Non-Null and typeA is nullable
              -
            1. Let innerTypeB be the inner type of typeB
            2. -
            3. Let mergedType be MergeOutputFieldType(typeA, innerTypeB)
            4. -
            5. return EnsureNonNullType(mergedType)
            6. -
            -
          8. -
          9. If both typeA and typeB are List
              -
            1. Let itemTypeA be the item type of typeA
            2. -
            3. Let itemTypeB be the item type of typeB
            4. -
            5. Let innerType be MergeOutputFieldType(itemTypeA, itemTypeB)
            6. -
            7. return ToListType(innerType)
            8. -
            -
          10. -
          11. raise composition error
          12. -
          -
          -

          Merging nullable and non-nullable types:

          -
          Example № 91# Subgraph A
          -input Input1 {
          -  field1: String
          -}
          -
          -# Subgraph B
          -input Input1 {
          -  field1: String!
          -}
          -
          -# Result
          -input Input1 {
          -  field1: String!
          -}
          -
          -

          Merging nullable and non-nullable list types:

          -
          Example № 92# Subgraph A
          -type Type1 {
          -  field1: [String]
          -}
          -
          -# Subgraph B
          -type Type1 {
          -  field1: [String!]
          -}
          -
          -# Subgraph C
          -type Type1 {
          -  field1: [String!]!
          -}
          -
          -# Result
          -type Type1 {
          -  field1: [String!]!
          -}
          -
          -
          -
          -

          4.2.12MergeOutputFieldType

          -

          This algorithm merges two output types. The merge will result in the most permissive type, while still being compatible with both output types. This ensures that the data contract between the GraphQL Gateway and the API consumer can be fulfilled.

          -
          -MergeOutputFieldType(typeA, typeB)
            -
          1. If typeA and typeB are the same
              -
            1. return typeA
            2. -
            -
          2. -
          3. If both typeA and typeB are Non-Null
              -
            1. Let innerTypeA be the inner type of typeA
            2. -
            3. Let innerTypeB be the inner type of typeB
            4. -
            5. Let innerType be MergeOutputFieldType(innerTypeA, innerTypeB)
            6. -
            7. return EnsureNonNullType(innerType)
            8. +
            9. 4Executor + +
                +
              1. 4.1Configuration
            10. -
            11. If typeA is Non-Null and typeB is nullable
                -
              1. Let innerTypeA be the inner type of typeA
              2. -
              3. Let mergedType be MergeOutputFieldType(innerTypeA, typeB)
              4. -
              5. return EnsureNullableType(mergedType)
              6. -
              -
            12. -
            13. If typeB is Non-Null and typeA is nullable
                -
              1. Let innerTypeB be the inner type of typeB
              2. -
              3. Let mergedType be MergeOutputFieldType(typeA, innerTypeB)
              4. -
              5. return EnsureNullableType(mergedType)
              6. -
              -
            14. -
            15. If both typeA and typeB are Lists:
                -
              1. Let itemTypeA be the item type of typeA.
              2. -
              3. Let itemTypeB be the item type of typeB.
              4. -
              5. Let innerType be MergeOutputFieldType(itemTypeA, itemTypeB)
              6. -
              7. return ToListType(innerType)
              8. -
              -
            16. -
            17. raise composition error
            18. -
            -
          -

          Merging nullable and non-nullable types:

          -
          Example № 93# Subgraph A
          -type Type1 {
          -  field1: String
          -}
          -
          -# Subgraph B
          -type Type1 {
          -  field1: String!
          -}
          -
          -# Result
          -type Type1 {
          -  field1: String
          -}
          -
          -

          Merging nullable and non-nullable list types:

          -
          Example № 94# Subgraph A
          -type Type1 {
          -  field1: [String!]
          -}
          -
          -# Subgraph B
          -type Type1 {
          -  field1: [String]!
          -}
          -
          -# Result
          -type Type1 {
          -  field1: [String]
          -}
          -
          -
          -
          -

          4.2.13EnsureNonNullType

          -

          When merging types this helper ensures that the specified type is a non-null type or it wraps the specified type as a non-null type.

          -
          -EnsureNonNullType(type)
            -
          1. If type is Non-Null
              -
            1. return type
            2. -
            -
          2. -
          3. Let nonNullType be a new Non-Null type with type as inner type
          4. -
          5. return nonNullType
          6. -
          -
          -
          Example № 95# Before
          -String
          -
          -# After
          -String!
          -
          -
          -
          -

          4.2.14EnsureNullableType

          -

          When merging types this helper ensures that the specified type is a nullable type or it returns the inner type of the non-null type.

          -
          -EnsureNullableType(type)
            -
          1. If type is Non-Null
              -
            1. Let innerType be the inner type of type
            2. -
            3. return innerType
            4. -
            -
          2. -
          3. return type
          4. -
          -
          -
          Example № 96# Before
          -String!
          -
          -# After
          -String
          -
          -
          -
          -

          4.2.15ToListType

          -

          This algorithm creates list type for the provided type.

          -
          -ToListType(type)
            -
          1. Let listType be a new List type with type as item type
          2. -
          3. return listType
          4. -
          -
          -
          Example № 97# Before
          -String
          -
          -# After
          -[String]
          -
          -
          -
          -
          -

          4.3Satisfiability

          -
          -
          -
          -

          5Executor

          -

          A distributed GraphQL executor acts as an orchestrator that uses schema metadata to rewrite a GraphQL request into a query plan. This plan resolves the required data from subgraphs and coerces this data into the result of the GraphQL request.

          -
          -

          5.1Configuration

          -

          The supergraph is a GraphQL IDL document that contains metadata for the query planner that describes the relationship between type system members and the type system members on subgraphs.

          -
          -
          -
          -

          6Shared Types

          -

          In this section we outline directives and types that are shared between the subgraph configuration and the gateway configuration document.

          -
          -

          6.1Name

          -
          scalar Name
          -
          -

          The scalar Name represents a valid GraphQL type name.

          -
          -
          -

          6.2FieldSelection

          -
          scalar FieldSelection
          -
          -

          The scalar FieldSelection represents a GraphQL field selection syntax.

          -
          Example № 98abc(def: 1) { ghi }
          -
          -
          -
          -
          -

          -§Index

          -
            -
          1. ArgumentsAremergeable
          2. -
          3. BuildSubgraphSchema
          4. -
          5. CommonArguments
          6. -
          7. CommonFields
          8. -
          9. ComposeConfiguration
          10. -
          11. EnsureNonNullType
          12. -
          13. EnsureNullableType
          14. -
          15. EnumAremergeable
          16. -
          17. FieldsAreMergeable
          18. -
          19. HasQueryRootType
          20. -
          21. InputFieldsAremergeable
          22. -
          23. InputFieldsHaveConsistentDefaults
          24. -
          25. IsEnumEmpty
          26. -
          27. IsExposed
          28. -
          29. IsInputObjectTypeEmpty
          30. -
          31. IsInterfaceTypeEmpty
          32. -
          33. IsObjectTypeEmpty
          34. -
          35. MergeArgument
          36. -
          37. MergeArguments
          38. -
          39. MergeEnumType
          40. -
          41. MergeInputField
          42. -
          43. MergeInputFieldType
          44. -
          45. MergeInputType
          46. -
          47. MergeInterfaceImplementation
          48. -
          49. MergeInterfaceType
          50. -
          51. MergeOutputField
          52. -
          53. MergeOutputFieldType
          54. -
          55. MergeOutputType
          56. -
          57. MergeSchema
          58. -
          59. MergeType
          60. -
          61. MergeUnionType
          62. -
          63. SameTypeShape
          64. -
          65. ToListType
          66. -
          67. ValidateArgumentDefaultValues
          68. -
          69. ValidateDefaultValue
          70. -
          71. ValidateInputFieldDefaultValues
          72. -
          -
          - - - -
          -
          - -
          1. 1Overview
          2. -
          3. 2Source Schema - -
              -
            1. 2.1Directives - -
                -
              1. 2.1.1@entityResolver
              2. -
              3. 2.1.2@is
              4. -
              5. 2.1.3@shareable
              6. -
              7. 2.1.4@require
              8. -
              9. 2.1.5@provides
              10. -
              11. 2.1.6@external
              12. -
              13. 2.1.7@override
              14. -
              15. 2.1.8@internal
              16. -
              17. 2.1.9Schemacoordinate
              18. -
              -
            2. -
            -
          4. -
          5. 3Supergraph
          6. -
          7. 4Composition - -
              -
            1. 4.1Validate - -
                -
              1. 4.1.1Types - -
                  -
                1. 4.1.1.1Semantical Equivalence
                2. -
                -
              2. -
              3. 4.1.2Composite Types - -
                  -
                1. 4.1.2.1Field Types Mergeable
                2. -
                3. 4.1.2.2Argument Types Mergeable
                4. -
                5. 4.1.2.3Arguments mergeable
                6. -
                7. 4.1.2.4Required Arguments Cannot Be Internal
                8. -
                9. 4.1.2.5Public Fields Cannot Reference Internals
                10. -
                -
              4. -
              5. 4.1.3Object Types - -
                  -
                1. 4.1.3.1Empty Merged Object Type
                2. -
                -
              6. -
              7. 4.1.4Input Object Types - -
                  -
                1. 4.1.4.1Input Field Types mergeable
                2. -
                3. 4.1.4.2Input With Different Fields
                4. -
                5. 4.1.4.3Empty Merged Input Object Type
                6. -
                7. 4.1.4.4Input Field Default Mismatch
                8. -
                9. 4.1.4.5Public Input Fields Cannot Reference Internals
                10. -
                11. 4.1.4.6Required Input Fields cannot be internal
                12. -
                -
              8. -
              9. 4.1.5Enum Types - -
                  -
                1. 4.1.5.1Values Must Be The Same Across Subgraphs
                2. -
                3. 4.1.5.2Default Value Uses Internals
                4. -
                5. 4.1.5.3Empty Merged Enum Type
                6. -
                -
              10. -
              11. 4.1.6Interface - -
                  -
                1. 4.1.6.1Empty Merged Interface Type
                2. -
                -
              12. -
              13. 4.1.7Union - -
                  -
                1. 4.1.7.1Union Type Members Cannot Reference Internals
                2. -
                -
              14. -
              15. 4.1.8Schema - -
                  -
                1. 4.1.8.1No Queries
                2. -
                -
              16. -
              17. 4.1.9Shared Functions - -
                  -
                1. 4.1.9.1Same Type Shape
                2. -
                3. 4.1.9.2Is Exposed
                4. -
                -
              18. -
              -
            2. -
            3. 4.2Compose - -
                -
              1. 4.2.1MergeObjectType
              2. -
              3. 4.2.2MergeInputType
              4. -
              5. 4.2.3MergeInterfaceType
              6. -
              7. 4.2.4MergeUnionType
              8. -
              9. 4.2.5MergeEnumType
              10. -
              11. 4.2.6MergeInputField
              12. -
              13. 4.2.7MergeOutputField
              14. -
              15. 4.2.8MergeArguments
              16. -
              17. 4.2.9MergeArgument
              18. -
              19. 4.2.10MergeInterfaceImplementation
              20. -
              21. 4.2.11MergeInputFieldType
              22. -
              23. 4.2.12MergeOutputFieldType
              24. -
              25. 4.2.13EnsureNonNullType
              26. -
              27. 4.2.14EnsureNullableType
              28. -
              29. 4.2.15ToListType
              30. -
              -
            4. -
            5. 4.3Satisfiability
            6. -
            -
          8. -
          9. 5Executor +
          10. 5Shared Types
              -
            1. 5.1Configuration
            2. -
            -
          11. -
          12. 6Shared Types - -
              -
            1. 6.1Name
            2. -
            3. 6.2FieldSelection
            4. +
            5. 5.1Name
            6. +
            7. 5.2FieldSelection
          13. -
          14. §Index
          diff --git a/index.html b/index.html index a2299cd..f4d973a 100644 --- a/index.html +++ b/index.html @@ -1 +1 @@ - GraphQL Composite Schemas Specification Versions

          GraphQL Composite Schemas

          Prerelease Working Draft Thu, Apr 4, 2024
          + GraphQL Composite Schemas Specification Versions

          GraphQL Composite Schemas

          Prerelease Working Draft Thu, Aug 1, 2024