Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BREAKING(feat(federation)): full @link support #1816

Merged
merged 12 commits into from
Sep 8, 2023

Conversation

dariuszkuc
Copy link
Collaborator

📝 Description

Introduce full @link support that includes namespacing and renaming of the imported elements.

The @link directive allows users to link definitions within the document to external schemas. It is the core feature of the Apollo federation v2. While imported elements still need to have their definitions in the local schema, @link allows users to namespace and/or rename those items to avoid any local type conflicts. By default, all external types that are not explicitly imported have to be namespaced using the spec name or a provided custom namespace.

Updated @link definition

directive @link(url: String!, as: String, import: [link__Import]) repeatable on SCHEMA

scalar link__Import
  • url - external specification url
  • as - optional custom namespace
  • import - list of elements to import, can either be simple Strings (e.g. @key) or custom imports that rename elements (e.g. { name: "@key", as: "@myKey" })

By default, graphql-kotlin will continue to apply @link directive using latest supported federation specification but will only auto-import federation specific directives up to version 2.3 and only if they are present (i.e. applied to an element) in the schema. All new fed v2.4+ won't be included in the auto-imports and instead will be namespaced with the spec name, e.g. @federation__authenticated.

Users can provide custom @link information by providing a schema object with @LinkDirective information, e.g.

@LinkDirective(url = "https://specs.apollo.dev/federation/v2.3", `as`: "fed", import = [LinkImport(name = "@key", `as` = "@myKey"), LinkImport(name = "@requires")])
class MyCustomLinkSchema

Will generate following schema

schema @link(as: "fed", import : [{name : "@key", as : "@myKey"}, "@requires"], url : "https://specs.apollo.dev/federation/v2.3"){
  query: Query
}

// directive imported with custom name
"Space separated list of primary keys needed to access federated object"
directive @myKey(fields: fed__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE

// directive imported with same name
"Specifies required input field set from the base type for a resolver"
directive @requires(fields: fed__FieldSet!) on FIELD_DEFINITION

// type imported with custom namespace
"Federation type representing set of fields"
scalar fed__FieldSet

When importing custom specifications, in order to be able to identify whether element is part of custom specification, we need to annotate it with new @LinkedSpec annotation. All federation directives were updated to rely on this mechanism, e.g.

@LinkedSpec(FEDERATION_SPEC)
@Repeatable
@GraphQLDirective(
    name = KEY_DIRECTIVE_NAME,
    description = KEY_DIRECTIVE_DESCRIPTION,
    locations = [DirectiveLocation.OBJECT, DirectiveLocation.INTERFACE]
)
annotation class KeyDirective(val fields: FieldSet, val resolvable: Boolean = true)

🔗 Related Issues

@dariuszkuc dariuszkuc added type: enhancement New feature or request changes: major Changes require a major version module: generator Issue affects the schema generator and federation code labels Jul 27, 2023
gradle/libs.versions.toml Outdated Show resolved Hide resolved
Introduce full `@link` support that includes namespacing and renaming of the imported elements.

The `@link` directive allows users to link definitions within the document to external schemas. It is the core feature of the Apollo federation v2. While imported elements still need to have their definitions in the local schema, `@link` allows users to namespace and/or rename those items to avoid any local type conflicts. By default, all external types that are not explicitly imported have to be namespaced using the spec name or a provided custom namespace.

Updated `@link` definition

```graphql
directive @link(url: String!, as: String, import: [link__Import]) repeatable on SCHEMA

scalar link__Import
```

* url - external specification url
* as - optional custom namespace
* import - list of elements to import, can either be simple Strings (e.g. `@key`) or custom imports that rename elements (e.g. `{ name: "@key", as: "@mykey" }`)

By default, `graphql-kotlin` will continue to apply `@link` directive using latest supported federation specification but will only auto-import federation specific directives up to version 2.3 and only if they are present (i.e. applied to an element) in the schema. All new fed v2.4+ won't be included in the auto-imports and instead will be namespaced with the spec name, e.g. `@federation__authenticated`.

Users can provide custom `@link` information by providing a schema object with `@LinkDirective` information, e.g.

```kotlin
@LinkDirective(url = "https://specs.apollo.dev/federation/v2.3", `as`: "fed", import = [LinkImport(name = "@key", `as` = "@mykey"), LinkImport(name = "@requires")])
class MyCustomLinkSchema
```

Will generate following schema

```graphql
schema @link(as: "fed", import : [{name : "@key", as : "@mykey"}, "@requires"], url : "https://specs.apollo.dev/federation/v2.3"){
  query: Query
}

// directive imported with custom name
"Space separated list of primary keys needed to access federated object"
directive @mykey(fields: fed__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE

// directive imported with same name
"Specifies required input field set from the base type for a resolver"
directive @requires(fields: fed__FieldSet!) on FIELD_DEFINITION

// type imported with custom namespace
"Federation type representing set of fields"
scalar fed__FieldSet
```

When importing custom specifications, in order to be able to identify whether element is part of custom specification, we need to annotate it with new `@LinkedSpec` annotation. All federation directives were updated to rely on this mechanism, e.g.

```kotlin
@LinkedSpec(FEDERATION_SPEC)
@repeatable
@GraphQLDirective(
    name = KEY_DIRECTIVE_NAME,
    description = KEY_DIRECTIVE_DESCRIPTION,
    locations = [DirectiveLocation.OBJECT, DirectiveLocation.INTERFACE]
)
annotation class KeyDirective(val fields: FieldSet, val resolvable: Boolean = true)
```
@dariuszkuc dariuszkuc marked this pull request as ready for review September 5, 2023 22:58
@dariuszkuc dariuszkuc merged commit 1401099 into ExpediaGroup:master Sep 8, 2023
14 checks passed
@dariuszkuc dariuszkuc deleted the fed_link branch September 8, 2023 20:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
changes: major Changes require a major version module: generator Issue affects the schema generator and federation code type: enhancement New feature or request
Development

Successfully merging this pull request may close these issues.

2 participants