@@ -3301,6 +3301,121 @@ type Bill {
33013301}
33023302```
33033303
3304+ ### Validate Shareable Directives
3305+
3306+ #### Invalid Field Sharing
3307+
3308+ **Error Code **
3309+
3310+ `INVALID_FIELD_SHARING `
3311+
3312+ **Severity **
3313+
3314+ ERROR
3315+
3316+ **Formal Specification **
3317+
3318+ - Let {typeNames } be the set of all object type names from all source schemas
3319+ that are not declared as `@internal `
3320+ - For each {typeName } in {typeNames }:
3321+ - Let {typeDefinitions } be the list of all object type definitions from all
3322+ source schemas with the name {typeName }.
3323+ - Let {fieldNames } be the set of all field names from all {typeDefinitions }
3324+ that are not declared as `@internal ` or `@external `, part of a `@key `
3325+ directive , or overridden .
3326+ - For each {fieldName } in {fieldNames }:
3327+ - Let {fieldDefinitions } be the list of all field definitions from
3328+ {typeDefinitions } with the name {fieldName }.
3329+ - If {fieldDefinitions } has more than one element :
3330+ - For each {fieldDefinition } in {fieldDefinitions }:
3331+ - {fieldDefinition } must be annotated with `@shareable `.
3332+
3333+ **Explanatory Text **
3334+
3335+ A field in a federated GraphQL schema may be marked `@shareable `, indicating
3336+ that the same field can be resolved by multiple schemas without conflict. When a
3337+ field is **not** marked as `@shareable ` (sometimes called "non-shareable" ), it
3338+ cannot be provided by more than one schema.
3339+
3340+ Field definitions marked as `@external ` and overridden fields are excluded when
3341+ validating whether a field is shareable. These annotations indicate specific
3342+ cases where field ownership lies with another schema or has been replaced.
3343+
3344+ **Examples**
3345+
3346+ In this example, the `User` type field `fullName` is marked as shareable in both
3347+ schemas, allowing them to serve consistent data for that field without conflict.
3348+
3349+ ```graphql example
3350+ # Schema A
3351+ type User @key (fields : " id" ) {
3352+ id : ID !
3353+ username : String
3354+ fullName : String @shareable
3355+ }
3356+
3357+ # Schema B
3358+ type User @key (fields : " id" ) {
3359+ id : ID !
3360+ fullName : String @shareable
3361+ email : String
3362+ }
3363+ ```
3364+
3365+ In the following example , `User .fullName ` is overridden in one schema and
3366+ therefore the field can be defined in the other schema without being marked as
3367+ `@shareable `.
3368+
3369+ ```graphql example
3370+ # Schema A
3371+ type User @key (fields : " id" ) {
3372+ id : ID !
3373+ fullName : String @override (from : "B" )
3374+ }
3375+
3376+ # Schema B
3377+ type User @key (fields : " id" ) {
3378+ id : ID !
3379+ fullName : String
3380+ }
3381+ ```
3382+
3383+ In the following example , `User .fullName ` is marked as `@external ` in one schema
3384+ and therefore the field can be defined in the other schema without being marked
3385+ as `@shareable `.
3386+
3387+ ```graphql example
3388+ # Schema A
3389+ type User @key (fields : " id" ) {
3390+ id : ID !
3391+ fullName : String @external
3392+ }
3393+
3394+ # Schema B
3395+ type User @key (fields : " id" ) {
3396+ id : ID !
3397+ fullName : String
3398+ }
3399+ ```
3400+
3401+ In the following counter -example , `User .fullName ` is non -shareable but is
3402+ defined and resolved by two different schemas , resulting in an
3403+ `INVALID_FIELD_SHARING ` error .
3404+
3405+ ```graphql counter -example
3406+ # Schema A
3407+ type User @key (fields : " id" ) {
3408+ id : ID !
3409+ fullName : String
3410+ }
3411+
3412+ # Schema B
3413+ type User @key (fields : " id" ) {
3414+ id : ID !
3415+ fullName : String
3416+ }
3417+ ```
3418+
33043419## Merge
33053420
33063421During this stage , all definitions from each source schema are combined into a
@@ -5924,46 +6039,41 @@ type Book {
59246039
59256040### Validate Shareable Directives
59266041
5927- #### Invalid Field Sharing
6042+ #### Invalid Shareable Usage
59286043
59296044**Error Code **
59306045
5931- `INVALID_FIELD_SHARING `
6046+ `INVALID_SHAREABLE_USAGE `
59326047
59336048**Severity **
59346049
59356050ERROR
59366051
59376052**Formal Specification **
59386053
5939- - Let {schema } be the merged composite execution schema .
5940- - Let {types} be the set of all object and interface types in {schema }.
6054+ - Let {schema } be one of the composed schemas .
6055+ - Let {types } be the set of types defined in {schema }.
59416056- For each {type } in {types }:
6057+ - If {type } is an interface type :
6058+ - For each field definition {field } in {type }:
6059+ - If {field } is annotated with `@shareable `, produce an
6060+ `INVALID_SHAREABLE_USAGE ` error .
59426061 - If {type } is the `Subscription ` type :
5943- - Let {fields } be the set of all fields in {type }.
5944- - For each {field } in {fields }:
5945- - If {field } is marked with `@shareable `:
5946- - Produce an `INVALID_FIELD_SHARING ` error .
5947- - Otherwise :
5948- - Let {fields } be the set of all fields on {type }.
5949- - For each {field } in {fields }:
5950- - If {field } is not part of a `@key ` directive :
5951- - Let {fieldDefinitions } be the set of all field definitions for {field }
5952- across all source schemas excluding fields marked with `@external ` or
5953- `@override `.
5954- - If {fieldDefinitions } has more than one element :
5955- - {field } must be marked as `@shareable ` in at least one schema .
6062+ - For each field definition {field } in {type }:
6063+ - If {field } is annotated with `@shareable `, produce an
6064+ `INVALID_SHAREABLE_USAGE ` error .
59566065
59576066**Explanatory Text **
59586067
5959- A field in a federated GraphQL schema may be marked ` @shareable `, indicating
5960- that the same field can be resolved by multiple schemas without conflict. When a
5961- field is **not** marked as `@shareable ` (sometimes called "non-shareable" ), it
5962- cannot be provided by more than one schema .
6068+ The ` @shareable ` directive is intended to indicate that a field on an ** object
6069+ type ** can be resolved by multiple schemas without conflict . As a result , it is
6070+ only valid to use `@shareable ` on fields ** of object types ** (or on the entire
6071+ object type itself) .
59636072
5964- Field definitions marked as `@external ` or `@override ` are excluded when
5965- validating whether a field is shareable. These annotations indicate specific
5966- cases where field ownership lies with another schema or has been replaced.
6073+ Applying `@shareable ` to interface fields is disallowed and violates the valid
6074+ usage of the directive . This rule prevents schema composition errors and data
6075+ conflicts by ensuring that `@shareable ` is used only in contexts where shared
6076+ field resolution is meaningful and unambiguous.
59676077
59686078Additionally, subscription root fields cannot be shared (i.e., they are
59696079effectively non-shareable), as subscription events from multiple schemas would
@@ -5972,84 +6082,26 @@ as shareable or to define it in multiple schemas triggers the same error.
59726082
59736083**Examples**
59746084
5975- In this example, the `User` type field `fullName` is marked as shareable in both
5976- schemas, allowing them to serve consistent data for that field without conflict.
5977-
5978- ```graphql example
5979- # Schema A
5980- type User @key (fields : " id" ) {
5981- id : ID !
5982- username : String
5983- fullName : String @shareable
5984- }
5985-
5986- # Schema B
5987- type User @key (fields : " id" ) {
5988- id : ID !
5989- fullName : String @shareable
5990- email : String
5991- }
5992- ```
5993-
5994- In the following example , `User .fullName ` is overridden in one schema and
5995- therefore the field can be defined in multiple schemas without being marked as
5996- `@shareable `.
5997-
5998- ```graphql example
5999- # Schema A
6000- type User @key (fields : " id" ) {
6001- id : ID !
6002- fullName : String @override (from : "B" )
6003- }
6004-
6005- # Schema B
6006- type User @key (fields : " id" ) {
6007- id : ID !
6008- fullName : String
6009- }
6010- ```
6011-
6012- In the following example , `User .fullName ` is marked as `@external ` in one schema
6013- and therefore the field can be defined in the other schema without being marked
6014- as `@shareable `.
6085+ In this example, the field `orderStatus` on the `Order` object type is marked
6086+ with `@shareable `, which is allowed. It signals that this field can be served
6087+ from multiple schemas without creating a conflict.
60156088
60166089```graphql example
6017- # Schema A
6018- type User @key (fields : " id" ) {
6019- id : ID !
6020- fullName : String @external
6021- }
6022-
6023- # Schema B
6024- type User @key (fields : " id" ) {
6090+ type Order {
60256091 id : ID !
6026- fullName : String
6092+ orderStatus : String @shareable
6093+ total : Float
60276094}
60286095```
60296096
6030- In the following counter -example , ` User . profile ` is non - shareable but is defined
6031- and resolved by two different schemas , resulting in an ` INVALID_FIELD_SHARING `
6032- error .
6097+ In this counter-example, the ` InventoryItem ` interface has a field ` sku ` marked
6098+ with ` @shareable ` , which is invalid usage. Marking an interface field as
6099+ shareable leads to an ` INVALID_SHAREABLE_USAGE ` error.
60336100
60346101``` graphql counter-example
6035- # Schema A
6036- type User @key (fields : " id" ) {
6037- id : ID !
6038- profile : Profile
6039- }
6040-
6041- type Profile {
6042- avatarUrl : String
6043- }
6044-
6045- # Schema B
6046- type User @key (fields : " id" ) {
6047- id : ID !
6048- profile : Profile
6049- }
6050-
6051- type Profile {
6052- avatarUrl : String
6102+ interface InventoryItem {
6103+ sku : ID ! @shareable
6104+ name : String
60536105}
60546106```
60556107
@@ -6074,63 +6126,6 @@ type Subscription {
60746126}
60756127```
60766128
6077- #### Invalid Shareable Usage
6078-
6079- **Error Code **
6080-
6081- `INVALID_SHAREABLE_USAGE `
6082-
6083- **Severity **
6084-
6085- ERROR
6086-
6087- **Formal Specification **
6088-
6089- - Let {schema } be one of the composed schemas .
6090- - Let {types } be the set of types defined in {schema }.
6091- - For each {type } in {types }:
6092- - If {type } is an interface type :
6093- - For each field definition {field } in {type }:
6094- - If {field } is annotated with `@shareable `, produce an
6095- `INVALID_SHAREABLE_USAGE ` error .
6096-
6097- **Explanatory Text **
6098-
6099- The `@shareable ` directive is intended to indicate that a field on an **object
6100- type ** can be resolved by multiple schemas without conflict . As a result , it is
6101- only valid to use `@shareable ` on fields **of object types ** (or on the entire
6102- object type itself).
6103-
6104- Applying `@shareable ` to interface fields is disallowed and violates the valid
6105- usage of the directive . This rule prevents schema composition errors and data
6106- conflicts by ensuring that `@shareable ` is used only in contexts where shared
6107- field resolution is meaningful and unambiguous.
6108-
6109- **Examples**
6110-
6111- In this example, the field `orderStatus` on the `Order` object type is marked
6112- with `@shareable `, which is allowed. It signals that this field can be served
6113- from multiple schemas without creating a conflict.
6114-
6115- ```graphql example
6116- type Order {
6117- id : ID !
6118- orderStatus : String @shareable
6119- total : Float
6120- }
6121- ```
6122-
6123- In this example, the ` InventoryItem ` interface has a field ` sku ` marked with
6124- ` @shareable ` , which is invalid usage. Marking an interface field as shareable
6125- leads to an ` INVALID_SHAREABLE_USAGE ` error.
6126-
6127- ``` graphql counter-example
6128- interface InventoryItem {
6129- sku : ID ! @shareable
6130- name : String
6131- }
6132- ```
6133-
61346129## Validate Satisfiability
61356130
61366131The final step confirms that the composite schema supports executable queries
0 commit comments