From e8b2265d3620bd4302d775134b38a0536541b1d5 Mon Sep 17 00:00:00 2001 From: Dariusz Kuc <9501705+dariuszkuc@users.noreply.github.com> Date: Fri, 12 Apr 2024 13:51:36 -0500 Subject: [PATCH] chore: start v8 development (#1951) ### :pencil: Description Bumps the gradle version to 8.0.0-SNAPSHOT and cuts the v7 docs. Files of interest are `gradle.properties` (bumps lib version) and `website/docusaurus.config.js` + `website/versions.json` (which cuts new v8 version but still point to v7 as current). All the docs under `website/versioned_docs/*` and `website/versioned_sidebars/version-7.x.x-sidebars.json` were auto generated by docusaurus when cutting v7 version. `website/docs` are now source of the v8 docs. ### :link: Related Issues --- gradle.properties | 2 +- website/docusaurus.config.js | 6 +- ...oader-level-dispatched-instrumentation.png | Bin 0 -> 139009 bytes ...nc-execution-exhausted-instrumentation.png | Bin 0 -> 212372 bytes .../version-7.x.x/assets/ktor-initializer.png | Bin 0 -> 65751 bytes .../assets/spring-initializer.png | Bin 0 -> 103292 bytes .../version-7.x.x/blogs-and-videos.md | 34 + .../client/client-customization.mdx | 126 ++++ .../version-7.x.x/client/client-features.mdx | 504 +++++++++++++ .../version-7.x.x/client/client-overview.mdx | 222 ++++++ .../client/client-serialization.mdx | 473 ++++++++++++ .../versioned_docs/version-7.x.x/examples.md | 52 ++ .../version-7.x.x/framework-comparison.md | 168 +++++ .../version-7.x.x/getting-started.mdx | 82 +++ .../plugins/gradle-plugin-tasks.mdx | 450 ++++++++++++ .../plugins/gradle-plugin-usage-client.mdx | 654 +++++++++++++++++ .../plugins/gradle-plugin-usage-graalvm.mdx | 270 +++++++ .../plugins/gradle-plugin-usage-sdl.mdx | 171 +++++ .../version-7.x.x/plugins/hooks-provider.mdx | 138 ++++ .../plugins/maven-plugin-goals.md | 259 +++++++ .../plugins/maven-plugin-usage-client.md | 456 ++++++++++++ .../plugins/maven-plugin-usage-graalvm.md | 538 ++++++++++++++ .../plugins/maven-plugin-usage-sdl.md | 77 ++ .../customizing-schemas/advanced-features.md | 30 + .../customizing-schemas/annotations.md | 14 + .../custom-type-reference.md | 97 +++ .../customizing-schemas/deprecating-schema.md | 46 ++ .../customizing-schemas/directives.md | 210 ++++++ .../customizing-schemas/documenting-schema.md | 41 ++ .../customizing-schemas/excluding-fields.md | 29 + .../customizing-schemas/generator-config.md | 76 ++ .../customizing-schemas/renaming-fields.md | 73 ++ .../restricting-input-output.md | 29 + .../execution/async-models.md | 151 ++++ .../execution/contextual-data.md | 30 + .../execution/data-fetching-environment.md | 47 ++ .../schema-generator/execution/exceptions.md | 37 + .../execution/fetching-data.md | 57 ++ .../execution/introspection.md | 46 ++ .../execution/optional-undefined-arguments.md | 75 ++ .../execution/subscriptions.md | 63 ++ .../federation/apollo-federation.mdx | 149 ++++ .../federation/federated-directives.md | 686 ++++++++++++++++++ .../federation/federated-schemas.md | 170 +++++ .../federation/federation-tracing.md | 40 + .../federation/type-resolution.md | 130 ++++ .../schema-generator-getting-started.mdx | 144 ++++ .../writing-schemas/arguments.md | 109 +++ .../schema-generator/writing-schemas/enums.md | 76 ++ .../writing-schemas/fields.md | 24 + .../writing-schemas/interfaces.md | 129 ++++ .../schema-generator/writing-schemas/lists.md | 45 ++ .../writing-schemas/nested-arguments.md | 76 ++ .../writing-schemas/nullability.md | 28 + .../writing-schemas/scalars.md | 269 +++++++ .../writing-schemas/schema.md | 53 ++ .../writing-schemas/unions.md | 139 ++++ .../automatic-persisted-queries.md | 147 ++++ .../data-loader-instrumentation.mdx | 316 ++++++++ .../server/data-loader/data-loader.md | 210 ++++++ .../server/graphql-context-factory.md | 66 ++ .../server/graphql-request-handler.md | 13 + .../server/graphql-request-parser.md | 39 + .../version-7.x.x/server/graphql-server.md | 35 + .../server/ktor-server/ktor-configuration.md | 201 +++++ .../ktor-server/ktor-graphql-context.md | 48 ++ .../ktor-server/ktor-http-request-response.md | 67 ++ .../server/ktor-server/ktor-overview.mdx | 106 +++ .../server/ktor-server/ktor-schema.md | 61 ++ .../server/ktor-server/ktor-subscriptions.md | 60 ++ .../server/server-subscriptions.md | 13 + .../server/spring-server/spring-beans.md | 103 +++ .../spring-server/spring-graphql-context.md | 33 + .../spring-http-request-response.md | 7 + .../server/spring-server/spring-overview.mdx | 85 +++ .../server/spring-server/spring-properties.md | 34 + .../server/spring-server/spring-schema.md | 94 +++ .../spring-server/spring-subscriptions.md | 61 ++ .../version-7.x.x-sidebars.json | 140 ++++ website/versions.json | 1 + 80 files changed, 10036 insertions(+), 4 deletions(-) create mode 100644 website/versioned_docs/version-7.x.x/assets/data-loader-level-dispatched-instrumentation.png create mode 100644 website/versioned_docs/version-7.x.x/assets/data-loader-level-sync-execution-exhausted-instrumentation.png create mode 100644 website/versioned_docs/version-7.x.x/assets/ktor-initializer.png create mode 100644 website/versioned_docs/version-7.x.x/assets/spring-initializer.png create mode 100644 website/versioned_docs/version-7.x.x/blogs-and-videos.md create mode 100644 website/versioned_docs/version-7.x.x/client/client-customization.mdx create mode 100644 website/versioned_docs/version-7.x.x/client/client-features.mdx create mode 100644 website/versioned_docs/version-7.x.x/client/client-overview.mdx create mode 100644 website/versioned_docs/version-7.x.x/client/client-serialization.mdx create mode 100644 website/versioned_docs/version-7.x.x/examples.md create mode 100644 website/versioned_docs/version-7.x.x/framework-comparison.md create mode 100644 website/versioned_docs/version-7.x.x/getting-started.mdx create mode 100644 website/versioned_docs/version-7.x.x/plugins/gradle-plugin-tasks.mdx create mode 100644 website/versioned_docs/version-7.x.x/plugins/gradle-plugin-usage-client.mdx create mode 100644 website/versioned_docs/version-7.x.x/plugins/gradle-plugin-usage-graalvm.mdx create mode 100644 website/versioned_docs/version-7.x.x/plugins/gradle-plugin-usage-sdl.mdx create mode 100644 website/versioned_docs/version-7.x.x/plugins/hooks-provider.mdx create mode 100644 website/versioned_docs/version-7.x.x/plugins/maven-plugin-goals.md create mode 100644 website/versioned_docs/version-7.x.x/plugins/maven-plugin-usage-client.md create mode 100644 website/versioned_docs/version-7.x.x/plugins/maven-plugin-usage-graalvm.md create mode 100644 website/versioned_docs/version-7.x.x/plugins/maven-plugin-usage-sdl.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/advanced-features.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/annotations.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/custom-type-reference.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/deprecating-schema.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/directives.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/documenting-schema.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/excluding-fields.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/generator-config.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/renaming-fields.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/restricting-input-output.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/execution/async-models.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/execution/contextual-data.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/execution/data-fetching-environment.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/execution/exceptions.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/execution/fetching-data.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/execution/introspection.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/execution/optional-undefined-arguments.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/execution/subscriptions.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/federation/apollo-federation.mdx create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/federation/federated-directives.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/federation/federated-schemas.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/federation/federation-tracing.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/federation/type-resolution.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/schema-generator-getting-started.mdx create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/arguments.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/enums.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/fields.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/interfaces.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/lists.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/nested-arguments.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/nullability.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/scalars.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/schema.md create mode 100644 website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/unions.md create mode 100644 website/versioned_docs/version-7.x.x/server/automatic-persisted-queries/automatic-persisted-queries.md create mode 100644 website/versioned_docs/version-7.x.x/server/data-loader/data-loader-instrumentation.mdx create mode 100644 website/versioned_docs/version-7.x.x/server/data-loader/data-loader.md create mode 100644 website/versioned_docs/version-7.x.x/server/graphql-context-factory.md create mode 100644 website/versioned_docs/version-7.x.x/server/graphql-request-handler.md create mode 100644 website/versioned_docs/version-7.x.x/server/graphql-request-parser.md create mode 100644 website/versioned_docs/version-7.x.x/server/graphql-server.md create mode 100644 website/versioned_docs/version-7.x.x/server/ktor-server/ktor-configuration.md create mode 100644 website/versioned_docs/version-7.x.x/server/ktor-server/ktor-graphql-context.md create mode 100644 website/versioned_docs/version-7.x.x/server/ktor-server/ktor-http-request-response.md create mode 100644 website/versioned_docs/version-7.x.x/server/ktor-server/ktor-overview.mdx create mode 100644 website/versioned_docs/version-7.x.x/server/ktor-server/ktor-schema.md create mode 100644 website/versioned_docs/version-7.x.x/server/ktor-server/ktor-subscriptions.md create mode 100644 website/versioned_docs/version-7.x.x/server/server-subscriptions.md create mode 100644 website/versioned_docs/version-7.x.x/server/spring-server/spring-beans.md create mode 100644 website/versioned_docs/version-7.x.x/server/spring-server/spring-graphql-context.md create mode 100644 website/versioned_docs/version-7.x.x/server/spring-server/spring-http-request-response.md create mode 100644 website/versioned_docs/version-7.x.x/server/spring-server/spring-overview.mdx create mode 100644 website/versioned_docs/version-7.x.x/server/spring-server/spring-properties.md create mode 100644 website/versioned_docs/version-7.x.x/server/spring-server/spring-schema.md create mode 100644 website/versioned_docs/version-7.x.x/server/spring-server/spring-subscriptions.md create mode 100644 website/versioned_sidebars/version-7.x.x-sidebars.json diff --git a/gradle.properties b/gradle.properties index 7ec07ec5c4..33f326d7f4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ group = com.expediagroup -version = 7.0.0-SNAPSHOT +version = 8.0.0-SNAPSHOT # build config org.gradle.caching=true diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index b252617b5f..d947e98dd0 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -21,14 +21,14 @@ module.exports = { { docs: { editUrl: "https://github.com/ExpediaGroup/graphql-kotlin/tree/master/website", - lastVersion: 'current', + lastVersion: '7.x.x', showLastUpdateAuthor: true, showLastUpdateTime: true, sidebarPath: require.resolve('./sidebars.js'), versions: { current: { - label: '7.x.x', - path: '' + label: 'pre-release', + path: '8.x.x' } } } diff --git a/website/versioned_docs/version-7.x.x/assets/data-loader-level-dispatched-instrumentation.png b/website/versioned_docs/version-7.x.x/assets/data-loader-level-dispatched-instrumentation.png new file mode 100644 index 0000000000000000000000000000000000000000..a83d8150da450d110bd1989cde71059f0d0f8781 GIT binary patch literal 139009 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 z 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®! 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 azQLKXY^AAeX_&qP{uE?Xr0XP2L;fGQ*%pxi literal 0 HcmV?d00001 diff --git a/website/versioned_docs/version-7.x.x/assets/data-loader-level-sync-execution-exhausted-instrumentation.png b/website/versioned_docs/version-7.x.x/assets/data-loader-level-sync-execution-exhausted-instrumentation.png new file mode 100644 index 0000000000000000000000000000000000000000..1a49d17f68ab57159b798d1fec96dd0f796a572c GIT binary patch literal 212372 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�x#>^vX~Hdpt9*8j7%ewTZny~VqC_>)2?p= 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�Q4nX&FR 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 bvhIzgluK4rzZ*;d{wXVH$miZPefGZqZ?!~z literal 0 HcmV?d00001 diff --git a/website/versioned_docs/version-7.x.x/assets/ktor-initializer.png b/website/versioned_docs/version-7.x.x/assets/ktor-initializer.png new file mode 100644 index 0000000000000000000000000000000000000000..8062374e796610b7caa5c8de1e1203226fc94497 GIT binary patch literal 65751 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 literal 0 HcmV?d00001 diff --git a/website/versioned_docs/version-7.x.x/assets/spring-initializer.png b/website/versioned_docs/version-7.x.x/assets/spring-initializer.png new file mode 100644 index 0000000000000000000000000000000000000000..bfd4a6301d305afd5fcb70a0b8ba800397239819 GIT binary patch literal 103292 zcmeFZcT`hdw>OG_SP)P_5s)HEuhM%F=~b$9PzZz;dJjbe6r|Sxq4(YqLKP{YO7Eaj zLPrQBw7?gh_c`ah=ezp+d&eF3WsD@7z4qE`?YZWffOeKRILt9`&CKpAvNQLZo12;S z4zjV_cJ|Qx@ZpoDnSWpV0NpU%7rKu2#AG9*?~m?&$J73Tlk=*h!S>E4y3=aTUiRQ( zH$N39YX@;E@{r@UzlV9T{52z%qAs}9DaqXe26D0lZf@>;oSD8=hU;|hH=;Q-@muPJO=m@SMi9*rofdPGFKGXIbXnZ{XX%k&LuLta#W>3)ByMMQ zGls1Fz)w>aVOA_-zBV#+ay>y7vO&RcJF;CvN$1yq^5obnZXRwP3p1Qx;g?4U=<>eCZ#pR`FL}1_vAzr7SB#!Gf<5Hpbimq6?>RP^5 z1gNUwuwsvI;#>;_;^1SCu3lk

OyHP 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 K^6ox*_WuAVo(R_f literal 0 HcmV?d00001 diff --git a/website/versioned_docs/version-7.x.x/blogs-and-videos.md b/website/versioned_docs/version-7.x.x/blogs-and-videos.md new file mode 100644 index 0000000000..1a4360c015 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/blogs-and-videos.md @@ -0,0 +1,34 @@ +--- +id: blogs-and-videos +title: Blogs & Videos +--- +Here are some links to other blog posts and videos which may provide further examples and reading. + +## graphql-kotlin + +Articles and videos specifically about `graphql-kotlin` + +- 📺  [Supercharge your GraphQL with Ktor and GraalVM (Dariusz Kuc)(KotlinConf 2023)](https://www.youtube.com/watch?v=gqQwTFeHOUU&list=PLlFc5cFwUnmwcJ7ZXyMmS70A9QFyUu1HI) (en) +- 📝  [GraphQL Kotlin 6.0.0 Release](https://medium.com/expedia-group-tech/graphql-kotlin-6-0-0-release-2227fd066dcd) +- 📝  [GraphQL Kotlin 4.0.0 Release](https://medium.com/expedia-group-tech/graphql-kotlin-4-0-0-release-eb87e150a192) +- 📺  [Bootiful GraphQL with Kotlin (Dariusz Kuc, Guillaume Scheibel)(Spring One 2020)](https://www.youtube.com/watch?v=t9He4vHZC24) (en) +- 📺  [Bootiful GraphQL with Kotlin (Dariusz Kuc)(GOTO Chicago 2020)](https://www.youtube.com/watch?v=1siPT1pTXFU) (en) +- 📝  [Introducing GraphQL Kotlin Client](https://medium.com/expedia-group-tech/introducing-graphql-kotlin-client-b32dc3061a6f) +- 📝  [Announcing graphql-kotlin 2.0!](https://medium.com/expedia-group-tech/graphql-kotlin-2-0-4006ea41f774) +- 📺  [Bootiful GraphQL with Kotlin (Dariusz Kuc, Guillaume Scheibel)(KotlinConf 2019)](https://www.youtube.com/watch?v=7YJyPXjLdug&index=25) (en) +- 📝  [Creating a Reactive GraphQL Server with Spring Boot and Kotlin](https://medium.com/expedia-group-tech/creating-a-reactive-graphql-server-with-spring-boot-and-kotlin-54aca7316470) +- 📝  [Apollo Federation in a GraphQL Kotlin Server](https://medium.com/expedia-group-tech/apollo-federation-in-a-graphql-kotlin-server-115cea51607a) +- 📝  [Creating GraphQL Schemas in Kotlin](https://medium.com/expedia-group-tech/creating-graphql-schemas-in-kotlin-aaaac0ab0672) +- 📝  [Release of graphql-kotlin 1.0.0!](https://medium.com/expedia-group-tech/release-of-graphql-kotlin-1-0-0-791ad85d3116) +- 📝  [graphql-kotlin: Generate a GraphQL schema from Kotlin code](https://medium.com/expedia-group-tech/graphql-kotlin-generate-a-graphql-schema-from-kotlin-code-21d1dc2f6e27) + +## GraphQL + +Articles and videos about how Expedia Group is using GraphQL + +- 📝  [Expedia Group Case Study: Bootiful APIs With GraphQL and Kotlin](https://kotlinlang.org/lp/server-side/case-studies/expedia) +- 📝  [Expedia Group Transforms Product Development with Apollo](https://www.apollographql.com/customers/expediagroup/) +- 📺  [Creating a federated schema for a global company (Shane Myrick)](https://youtu.be/MuD3TAP0D9Y) (en) +- 📺  [Migrer ses APIs vers GraphQL: pourquoi? comment! (Guillaume Scheibel)](https://youtu.be/IRIkpvJo95s) (fr) +- 📺  [Migrate your APIs to GraphQL: how? and why! (Guillaume Scheibel)](https://youtu.be/IkPMpzQ-TRI) (en) +- 📺  [Transforming customer experiences and your organization with GraphQL (Jim Gust, Dan Boerner)](https://youtu.be/Jt-ZD4zj4Ow) (en) diff --git a/website/versioned_docs/version-7.x.x/client/client-customization.mdx b/website/versioned_docs/version-7.x.x/client/client-customization.mdx new file mode 100644 index 0000000000..072892f956 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/client/client-customization.mdx @@ -0,0 +1,126 @@ +--- +id: client-customization +title: Client Customization +--- + + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Ktor HTTP Client Customization + +`GraphQLKtorClient` is a thin wrapper on top of [Ktor HTTP Client](https://ktor.io/docs/client.html) and supports fully +asynchronous non-blocking communication. It is highly customizable and can be configured with any supported Ktor HTTP +[engine](https://ktor.io/clients/http-client/engines.html) and [features](https://ktor.io/clients/http-client/features.html). + +See [Ktor HTTP Client documentation](https://ktor.io/clients/index.html) for additional details. + +### Global Client Customization + +A single instance of `GraphQLKtorClient` can be used to handle many GraphQL operations. You can specify a custom instance +of Ktor `HttpClient` and a target `GraphQLClientSerializer`. + +The below example configures a new `GraphQLKtorClient` to use the `OkHttp` engine with custom timeouts, adds a default `X-MY-API-KEY` +header to all requests, and enables basic logging of the requests. + +```kotlin +val okHttpClient = HttpClient(engineFactory = OkHttp) { + engine { + config { + connectTimeout(10, TimeUnit.SECONDS) + readTimeout(60, TimeUnit.SECONDS) + writeTimeout(60, TimeUnit.SECONDS) + } + } + defaultRequest { + header("X-MY-API-KEY", "someSecretApiKey") + } + install(Logging) { + logger = Logger.DEFAULT + level = LogLevel.INFO + } +} +val client = GraphQLKtorClient( + url = URL("http://localhost:8080/graphql"), + httpClient = okHttpClient +) +``` + +### Per Request Customization + +Individual GraphQL requests can be customized through [HttpRequestBuilder](https://ktor.io/docs/request.html#customizing-requests). +You can use this mechanism to specify custom headers, update target url to include custom query parameters, configure +attributes that can be accessed from the pipeline features as well specify timeouts per request. + +```kotlin +val helloWorldQuery = HelloWorldQuery(variables = HelloWorldQuery.Variables(name = "John Doe")) +val result = client.execute(helloWorldQuery) { + header("X-B3-TraceId", "0123456789abcdef") +} +``` + +## Spring WebClient Customization + +`GraphQLWebClient` is a thin wrapper on top of [Spring WebClient](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/reactive/function/client/WebClient.html) +that relies on Reactor Netty for fully asynchronous non-blocking communications. If you want to use Jetty instead you will +need to exclude provided `io.projectreactor.netty:reactor-netty` dependency and instead add `org.eclipse.jetty:jetty-reactive-httpclient` +dependency. + +### Global Client Customization + +A single instance of `GraphQLWebClient` can be used to handle many GraphQL operations and you can customize it by providing +a custom instance of `WebClient.Builder`. See [Spring documentation](https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-webclient-customization) +for additional details. + +Example below configures `GraphQLWebClient` with custom timeouts and adds a default `X-MY-API-KEY` header to all requests. + +```kotlin +val httpClient: HttpClient = HttpClient.create() + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10_000) + .responseTimeout(Duration.ofMillis(10_000)) +val connector: ClientHttpConnector = ReactorClientHttpConnector(httpClient.wiretap(true)) +val webClientBuilder = WebClient.builder() + .clientConnector(connector) + .defaultHeader("X-MY-API-KEY", "someSecretApiKey") + +val client = GraphQLWebClient( + url = "http://localhost:8080/graphql", + builder = webClientBuilder +) +``` + +### Per Request Customization + +Individual GraphQL requests can be customized by providing `WebClient.RequestBodyUriSpec` lambda. You can use this mechanism +to specify custom headers or include custom attributes or query parameters. + +```kotlin +val helloWorldQuery = HelloWorldQuery(variables = HelloWorldQuery.Variables(name = "John Doe")) +val result = client.execute(helloWorldQuery) { + header("X-B3-TraceId", "0123456789abcdef") +} +``` + +## Custom GraphQL Client + +GraphQL Kotlin libraries provide generic a `GraphQLClient` interface as well as Ktor HTTP Client and Spring WebClient based +reference implementations. Both `GraphQLKtorClient` and `GraphQLWebClient` are open classes which means you can also +extend them to provide some custom `execute` logic. + +```kotlin +class CustomGraphQLClient(url: URL) : GraphQLKtorClient(url = url) { + + override suspend fun execute(request: GraphQLClientRequest, requestCustomizer: HttpRequestBuilder.() -> Unit): GraphQLClientResponse { + // custom init logic + val result = super.execute(request, requestCustomizer) + // custom finalize logic + return result + } +} +``` + +## Deprecated Field Usage + +Build plugins will automatically fail generation of a client if any of the specified query files are referencing +deprecated fields. This ensures that your clients have to explicitly opt-in into deprecated usage by specifying +`allowDeprecatedFields` configuration option. diff --git a/website/versioned_docs/version-7.x.x/client/client-features.mdx b/website/versioned_docs/version-7.x.x/client/client-features.mdx new file mode 100644 index 0000000000..4bfd3b8e42 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/client/client-features.mdx @@ -0,0 +1,504 @@ +--- +id: client-features +title: Client Features +--- + + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Jackson and Kotlinx Serialization Support + +GraphQL Kotlin supports generation of client data models that are compatible with both `Jackson` (default) and `kotlinx.serialization` +formats. Build plugins and `graphql-kotlin-spring-client` default to use `Jackson` whereas `graphql-kotlin-ktor-client` +defaults to `kotlinx.serialization`. + +See [client serialization documentation](./client-serialization.mdx) for additional details. + +## Polymorphic Types Support + +GraphQL supports polymorphic types through unions and interfaces which can be represented in Kotlin as marker and +regular interfaces. In order to ensure generated objects are not empty, GraphQL queries referencing polymorphic types +will automatically generate fallback implementations that will be used if there is no match. Polymorphic queries have to +explicitly request `__typename` field as it is used by serializers to correctly distinguish between different implementations. + +:::caution +`kotlinx-serialization` currently does not provide mechanism to automatically register polymorphic fallbacks. Fallbacks +have to be explicitly configured when creating your `GraphQLClientKotlinxSerializer`. + +```kotlin +val serializerWithFallback = GraphQLClientKotlinxSerializer(jsonBuilder = { + serializersModule = SerializersModule { + polymorphic(BasicInterface::class) { + defaultDeserializer { DefaultBasicInterfaceImplementation.serializer() } + } + } +}) +val client = GraphQLKtorClient(url = URL("http://localhost:8080/graphql"), serializer = serializerWithFallback) +``` + +See https://github.com/Kotlin/kotlinx.serialization/issues/1575 for details. +::: + +Given example schema + +```graphql +type Query { + interfaceQuery: BasicInterface! +} + +interface BasicInterface { + id: Int! + name: String! +} + +type FirstInterfaceImplementation implements BasicInterface { + id: Int! + intValue: Int! + name: String! +} + +type SecondInterfaceImplementation implements BasicInterface { + floatValue: Float! + id: Int! + name: String! +} +``` + +We can query interface field as + +```graphql +query PolymorphicQuery { + interfaceQuery { + __typename + id + name + ... on FirstInterfaceImplementation { + intValue + } + ... on SecondInterfaceImplementation { + floatValue + } + } +} +``` + +Which will generate following data models + + + + + +```kotlin +@Generated +@JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.PROPERTY, + property = "__typename", + defaultImpl = DefaultBasicInterfaceImplementation::class +) +@JsonSubTypes(value = [com.fasterxml.jackson.annotation.JsonSubTypes.Type(value = + FirstInterfaceImplementation::class, + name="FirstInterfaceImplementation"),com.fasterxml.jackson.annotation.JsonSubTypes.Type(value + = SecondInterfaceImplementation::class, name="SecondInterfaceImplementation")]) +interface BasicInterface { + abstract val id: Int + abstract val name: String +} + +@Generated +data class FirstInterfaceImplementation( + override val id: Int, + override val name: String, + val intValue: Int +) : BasicInterface + +@Generated +data class SecondInterfaceImplementation( + override val id: Int, + override val name: String, + val floatValue: Float +) : BasicInterface + +@Generated +data class DefaultBasicInterfaceImplementation( + override val id: Int, + override val name: String +) : BasicInterface +``` + + + + +```kotlin +@Generated +@Serializable +sealed class BasicInterface { + abstract val id: Int + abstract val name: String +} + +@Generated +@Serializable +@SerialName(value = "FirstInterfaceImplementation") +data class FirstInterfaceImplementation( + override val id: Int, + override val name: String, + val intValue: Int +) : BasicInterface() + +@Generated +@Serializable +@SerialName(value = "SecondInterfaceImplementation") +data class SecondInterfaceImplementation( + override val id: Int, + override val name: String, + val floatValue: Float +) : BasicInterface() + +@Generated +@Serializable +data class DefaultBasicInterfaceImplementation( + override val id: String + override val name: String +) : BasicInterface() +``` + + + + +## Custom Scalar Support + +By default, custom GraphQL scalars are serialized and [type-aliased](https://kotlinlang.org/docs/reference/type-aliases.html) +to a String. GraphQL Kotlin plugins also support custom serialization based on provided configuration. + +In order to automatically convert between custom GraphQL `UUID` scalar type and `java.util.UUID`, we first need to create +our custom `ScalarConverter`. + +```kotlin +package com.example.client + +import com.expediagroup.graphql.client.converter.ScalarConverter +import java.util.UUID + +class UUIDScalarConverter : ScalarConverter { + override fun toScalar(rawValue: Any): UUID = UUID.fromString(rawValue.toString()) + override fun toJson(value: UUID): Any = value.toString() +} +``` + +And then configure build plugin by specifying + +- Custom GraphQL scalar name +- Target JVM class name +- Converter that provides logic to map between GraphQL and Kotlin type + +```kotlin +graphql { + packageName = "com.example.generated" + endpoint = "http://localhost:8080/graphql" + customScalars = listOf(GraphQLScalar("UUID", "java.util.UUID", "com.example.UUIDScalarConverter")) +} +``` + +Custom scalar fields will then be automatically converted to a `java.util.UUID` type using appropriate converter/serializer. + + + + + +Following converters will be generated under `com.example.generated.scalars` package. + +```kotlin +@Generated +public class AnyToUUIDConverter : StdConverter() { + private val converter: UUIDScalarConverter = UUIDScalarConverter() + + public override fun convert(`value`: Any): UUID = converter.toScalar(value) +} + +@Generated +public class UUIDToAnyConverter : StdConverter() { + private val converter: UUIDScalarConverter = UUIDScalarConverter() + + public override fun convert(`value`: UUID): Any = converter.toJson(value) +} +``` + +Custom scalars fields will then be annotated with Jackson annotations referencing the above converters. + +```kotlin +@Generated +public data class Result( + @JsonSerialize(converter = UUIDToAnyConverter::class) + @JsonDeserialize(converter = AnyToUUIDConverter::class) + public val custom: UUID, + @JsonSerialize(contentConverter = UUIDToAnyConverter::class) + @JsonDeserialize(contentConverter = AnyToUUIDConverter::class) + public val customList: List +) +``` + + + + +Following serializer will be generated under `com.example.generated.scalars` package. + +```kotlin +@Generated +public object UUIDSerializer : KSerializer { + private val converter: UUIDScalarConverter = UUIDScalarConverter() + + public override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("UUID", STRING) + + public override fun serialize(encoder: Encoder, `value`: UUID): Unit { + val encoded = converter.toJson(value) + encoder.encodeString(encoded.toString()) + } + + public override fun deserialize(decoder: Decoder): UUID { + val jsonDecoder = decoder as JsonDecoder + val element = jsonDecoder.decodeJsonElement() + val rawContent = element.jsonPrimitive.content + return converter.toScalar(rawContent) + } +} +``` + +Custom scalars fields will then be annotated with `@Serializable` annotation referencing the above serializer. + +```kotlin +@Generated +@Serializable +public data class Result( + @Serializable(with = UUIDSerializer::class) + public val custom: UUID, + public val customList: List<@Serializable(with = UUIDSerializer::class) UUID> +) +``` + + + + +See [Gradle](../plugins/gradle-plugin-tasks.mdx) and [Maven](../plugins/maven-plugin-goals.md) plugin documentation for additional details. + +:::info +While custom scalars are most commonly represented using some primitive values (e.g. serializing UUID as String), it is +possible to use arbitrary objects representation as custom scalar. For example Apollo Federation relies on `_Any` scalar +to accept federated entity representations which is a JSON map containing `__typename` information and a number of additional +fields used to uniquely identify the target object. + + + + + +Jackson uses reflection to automatically serialize the objects. In order to rely on this behavior for custom scalars, +we simply need to implement a pass-through converter. + +```kotlin +class AnyScalarConverter : ScalarConverter { + override fun toScalar(rawValue: Any): Any = rawValue + override fun toJson(value: Any): Any = value +} +``` + +This will allow us to pass arbitrary objects as custom scalar inputs. Given following Federation type and `_entities` query + +``` +type Product @key(fields : "id") { + id: String! + name: String! +} + +query EntitiesQuery($representations: [_Any!]!) { + _entities(representations: $representations) { + __typename + ...on Product { name } + } + } +} +``` + +We can create corresponding `ProductEntityRepresentation` data class and use it in our generated query. + +```kotlin +data class ProductEntityRepresentation(val id: String) { + val __typename: String = "Product" +} + +val entityData = client.execute(EntitiesQuery(variables = EntitiesQuery.Variables(representations = listOf(ProductEntityRepresentation(id = "apollo-federation"))))) +``` + + + + +Using kotlinx-serialization we can use `JsonObject` to represent arbitrary objects as custom scalars. + +```kotlin +class AnyScalarConverter : ScalarConverter { + override fun toScalar(rawValue: Any): JsonObject = Json.parseToJsonElement(rawValue.toString()).jsonObject + override fun toJson(value: JsonObject): Any = value +} +``` + +This will allow us to pass arbitrary objects as custom scalar inputs. Given following Federation type and `_entities` query + +``` +type Product @key(fields : "id") { + id: String! + name: String! +} + +query EntitiesQuery($representations: [_Any!]!) { + _entities(representations: $representations) { + __typename + ...on Product { name } + } + } +} +``` + +We can then represent product entity representation as `JsonObject` and use it in our generated query. + +```kotlin +val entity = Json.decodeFromString( + """ + |{ + | "__typename": "Product", + | "id": "apollo-federation" + |} + """.trimMargin() +) + +val entityData = client.execute(EntitiesQuery(variables = EntitiesQuery.Variables(representations = listOf(entity)))) +``` + + + +::: + +## Default Enum Values + +Enums represent predefined set of values. Adding additional enum values could be a potentially breaking change as your +clients may not be able to process it. GraphQL Kotlin Client automatically adds default `__UNKNOWN_VALUE` to all generated +enums as a catch all safeguard for handling new enum values. + +## Auto Generated Documentation + +GraphQL Kotlin build plugins automatically pull in GraphQL descriptions of the queried fields from the target schema and +add it as KDoc to corresponding data models. + +Given simple GraphQL object definition + +```graphql +"Some basic description" +type BasicObject { + "Unique identifier" + id: Int! + "Object name" + name: String! +} +``` + +Will result in a corresponding auto generated data class + +```kotlin +/** + * Some basic description + */ + @Generated +data class BasicObject( + /** + * Unique identifier + */ + val id: Int, + /** + * Object name + */ + val name: String +) +``` + +## Native Support for Coroutines + +GraphQL Kotlin Client is a generic interface that exposes `execute` methods that will suspend your GraphQL operation until +it gets a response back without blocking the underlying thread. Reference Ktor and Spring WebClient based implementations +offer fully asynchronous communication through Kotlin coroutines. In order to fetch data asynchronously you should wrap +your client execution in `launch` or `async` coroutine builder and explicitly `await` for their results. + +See [Kotlin coroutines documentation](https://kotlinlang.org/docs/reference/coroutines-overview.html) for additional details. + +## Batch Operation Support + +GraphQL Kotlin Clients provide out of the box support for batching multiple client operations into a single GraphQL request. +Batch requests are sent as an array of individual GraphQL requests and clients expect the server to respond with a corresponding +array of GraphQL responses. Each response is then deserialized to a corresponding result type. + +```kotlin +val client = GraphQLKtorClient(url = URL("http://localhost:8080/graphql")) +val firstQuery = FirstQuery(variables = FirstQuery.Variables(foo = "bar")) +val secondQuery = SecondQuery(variables = SecondQuery.Variables(foo = "baz")) + +val results: List> = client.execute(listOf(firstQuery, secondQuery)) +``` + +## Optional Input Support + +In the GraphQL world, input types can be optional which means that the client can specify a value, specify a `null` value +OR don't specify any value. This is in contrast with the JVM world where objects can either have some specific value or +don't have any value (i.e. are `null`). By default, GraphQL Kotlin Client treats `null` Kotlin values as unspecified, which +means they will skip all `null` values when serializing the request, e.g. given following query + +```graphql +query OptionalInputQuery($optionalValue: String) { + optional(value: $optionalValue) +``` + +GraphQL Kotlin plugins will generate corresponding POJO that defines `Variables` as + +```kotlin +public data class Variables( + public val optionalValue: String? = null +) +``` + +Regardless whether we specify `optionalValue` as `null` or rely on the default value, this field won't be serialized, +i.e. variables will be serialized as an empty JSON object `{}`. + +By specifying `useOptionalInputWrapper = true` plugin configuration option, we can opt-in to a behavior that supports +three states - defined, `null` or undefined. Generated code will then use `OptionalInput` wrapper to represent those states. +See [Gradle](../plugins/gradle-plugin-tasks) and [Maven](../plugins/maven-plugin-goals) plugin for configuration details. + +```kotlin +public data class Variables( + public val optionalValue: OptionalInput = OptionalInput.Undefined +) + +// usage +// - same behavior as default null, serialized as {} +val undefinedVariables = Variables(optionalValue = OptionalInput.Undefined) + +// - serialized as {"optionalValue": null} +val nullVariables = Variables(optionalValue = OptionalInput.Defined(null)) + +// - serialized as {"optionalValue": "foo"} +val definedVariables = Variables(optionalValue = OptionalInput.Defined("foo") +``` diff --git a/website/versioned_docs/version-7.x.x/client/client-overview.mdx b/website/versioned_docs/version-7.x.x/client/client-overview.mdx new file mode 100644 index 0000000000..ab0c7bc097 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/client/client-overview.mdx @@ -0,0 +1,222 @@ +--- +id: client-overview +title: Client Overview +--- + + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +GraphQL Kotlin provides a set of lightweight type-safe GraphQL HTTP clients. The library provides [Ktor HTTP client](https://ktor.io/clients/index.html) +and [Spring WebClient](https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-webclient) +based reference implementations as well as allows for custom implementations using other engines, see [client customization](client-customization.mdx) +documentation for additional details. Type-safe data models are generated at build time by the GraphQL Kotlin [Gradle](../plugins/gradle-plugin-tasks.mdx) +and [Maven](../plugins/maven-plugin-goals.md) plugins. + +Client Features: + +- Supports query and mutation operations +- Supports batch operations +- Automatic generation of type-safe Kotlin models supporting `kotlinx.serialization` and `Jackson` formats +- Custom scalar support - defaults to String but can be configured to deserialize to specific types +- Supports default enum values to gracefully handle new/unknown server values +- Native support for coroutines +- Easily configurable Ktor and Spring WebClient based HTTP Clients +- Documentation generated from the underlying GraphQL schema + +## Project Configuration + +GraphQL Kotlin provides both Gradle and Maven plugins to automatically generate your client code at build time. In order +to auto-generate the client code, plugins require target GraphQL schema and a list of query files to process. + +GraphQL schema can be provided as + +- result of introspection query (default) +- downloaded from an SDL endpoint +- local file + +See [Gradle](https://expediagroup.github.io/graphql-kotlin/docs/plugins/gradle-plugin) and [Maven](https://expediagroup.github.io/graphql-kotlin/docs/plugins/maven-plugin) +plugin documentation for additional details. + +GraphQL Kotlin plugins generated classes are simple POJOs that implement `GraphQLClientRequest` and optionally accept variables +(only if underlying operation uses variables) as a constructor parameter. Generated classes can then be passed directly +to a GraphQL client to execute either a single or a batch request. + +Example below configures the project to use introspection query to obtain the schema and uses Spring WebClient based HTTP client. + +### Build Configuration + + + + + +Basic `build.gradle.kts` Gradle configuration that executes introspection query against specified endpoint to obtain target +schema and then generate the clients under `com.example.generated` package name: + +```kotlin +import com.expediagroup.graphql.plugin.gradle.graphql + +plugins { + id("com.expediagroup.graphql") version $latestGraphQLKotlinVersion +} + +dependencies { + implementation("com.expediagroup:graphql-kotlin-spring-client:$latestGraphQLKotlinVersion") +} + +graphql { + client { + endpoint = "http://localhost:8080/graphql" + packageName = "com.example.generated" + } +} +``` + + + + +Basic Maven `pom.xml` configuration that executes introspection query against specified endpoint to obtain target +schema and then generate the clients under `com.example.generated` package name: + +```xml + + + 4.0.0 + + com.example + graphql-kotlin-maven-client-example + 1.0.0-SNAPSHOT + + + $latestGraphQLKotlinVersion + + + + + com.expediagroup + graphql-kotlin-spring-client + ${graphql-kotlin.version} + + + + + + + com.expediagroup + graphql-kotlin-maven-plugin + ${graphql-kotlin.version} + + + generate-graphql-client + + introspect-schema + generate-client + + + http://localhost:8080/graphql + com.example.generated + ${project.build.directory}/schema.graphql + + + + + + + +``` + + + + +See [graphql-kotlin-client-example](https://github.com/ExpediaGroup/graphql-kotlin/tree/master/examples/client) project for complete +working examples of Gradle and Maven based projects. + +### Generating GraphQL Operations + +By default, GraphQL Kotlin build plugins will attempt to generate GraphQL operations from all `*.graphql` files located under +`src/main/resources`. Operations are validated against the target GraphQL schema, which can be manually provided, retrieved by +the plugins through introspection (as configured in examples above) or downloaded directly from a custom SDL endpoint. +See our documentation for more details on supported [Gradle tasks](../plugins/gradle-plugin-tasks.mdx) +and [Maven Mojos](../plugins/maven-plugin-goals.md). + +When creating your GraphQL operations make sure to always specify an operation name and name the files accordingly. Each +one of your GraphQL operation files will generate a corresponding Kotlin file with a class matching your operation +name. Input objects, enums and custom scalars definitions will be shared across different operations. All other objects +will be generated operation specific package name. For example, given `HelloWorldQuery.graphql` with `HelloWorldQuery` as +the operation name, GraphQL Kotlin plugins will generate a corresponding `HelloWorldQuery.kt` file with a `HelloWorldQuery` +class under the configured package. + +For example, given a simple schema + +```graphql +type Query { + helloWorld: String +} +``` + +And a corresponding `HelloWorldQuery.graphql` query + +```graphql +query HelloWorldQuery { + helloWorld +} +``` + +Plugins will generate following client code + +```kotlin +package com.example.generated + +import com.expediagroup.graphql.client.Generated +import com.expediagroup.graphql.client.types.GraphQLClientRequest +import kotlin.String +import kotlin.reflect.KClass + +const val HELLO_WORLD_QUERY: String = "query HelloWorldQuery {\n helloWorld\n}" + +@Generated +class HelloWorldQuery: GraphQLClientRequest { + override val query: String = HELLO_WORLD_QUERY + + override val operationName: String = "HelloWorldQuery" + + override fun responseType(): KClass = HelloWorldQuery.Result::class + + @Generated + data class Result( + val helloWorld: String + } +} +``` + +Generated classes are simple POJOs that implement `GraphQLClientRequest` interface and represent a GraphQL request. + +### Executing Operations + +`GraphQLWebClient` uses the Spring WebClient to execute the underlying operations and allows you to customize it by providing +an instance of `WebClient.Builder`. `GraphQLWebClient` requires target URL to be specified and defaults to use `Jackson` +based GraphQL serializer. Please refer to [Spring documentation](https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-client) +for additional details. + +```kotlin +package com.example.client + +import com.expediagroup.graphql.client.spring.GraphQLWebClient +import com.expediagroup.graphql.generated.HelloWorldQuery +import kotlinx.coroutines.runBlocking + +fun main() { + val client = GraphQLWebClient(url = "http://localhost:8080/graphql") + runBlocking { + val helloWorldQuery = HelloWorldQuery() + val result = client.execute(helloWorldQuery) + println("hello world query result: ${result.data?.helloWorld}") + } +} +``` diff --git a/website/versioned_docs/version-7.x.x/client/client-serialization.mdx b/website/versioned_docs/version-7.x.x/client/client-serialization.mdx new file mode 100644 index 0000000000..cfb226e743 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/client/client-serialization.mdx @@ -0,0 +1,473 @@ +--- +id: client-serialization +title: Client Serialization +--- + + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +GraphQL Kotlin build plugins can generate GraphQL client data classes that are compatible with [`Jackson`](https://github.com/FasterXML/jackson) +(default) or [`kotlinx.serialization`](https://github.com/Kotlin/kotlinx.serialization) data models. By default, GraphQL +clients will attempt to pick up the appropriate serializer from a classpath - `graphql-kotlin-spring-client` defines implicit +dependency on `Jackson` based serializer and `graphql-kotlin-ktor-client` define a dependency on a `kotlinx.serialization`. + +`GraphQLClientSerializer` is a service provider interface that expose generic serialize/deserialize methods that are used +by the GraphQL clients to serialize requests to String and deserialize responses from String. By utilizing Java [ServiceLoader](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ServiceLoader.html) +mechanism we can dynamically load appropriate serializer from the classpath. If there are multiple providers on the classpath, +we default to select the first one available one on the classpath. + +## GraphQL Kotlin Spring Client + +### Using Jackson + +`Jackson` is the default serializer used by the build plugins and by GraphQL Kotlin Spring Client. + + + + + +```kotlin +// build.gradle.kts +import com.expediagroup.graphql.plugin.gradle.graphql + +dependencies { + implementation("com.expediagroup", "graphql-kotlin-spring-client", $graphQLKotlinVersion) { +} + +graphql { + client { + endpoint = "http://localhost:8080/graphql" + packageName = "com.example.generated" + } +} +``` + + + + +```xml + + + + + com.expediagroup + graphql-kotlin-spring-client + ${graphql-kotlin.version} + + + + + + + + com.expediagroup + graphql-kotlin-maven-plugin + ${graphql-kotlin.version} + + + + introspect-schema + generate-client + + + http://localhost:8080/graphql + com.example.generated + + + + + + + +``` + + + + +By default, `ServiceLoader` mechanism will load the first available GraphQL client serializer from the classpath. + +```kotlin +val client = GraphQLWebClient( + url = "http://localhost:8080/graphql" + serializer = GraphQLClientJacksonSerializer() +) +``` + +### Using Kotlinx Serialization + +In order to use `kotlinx.serialization` we need to + +* add dependency on `graphql-kotlin-client-serialization` +* configure GraphQL plugin to generate `kotlinx.serialization` compatible data models +* configure corresponding compiler plugin +* explicitly specify the target serializer during client construction OR exclude `graphql-kotlin-client-jackson` dependency + + + + + +```kotlin +// build.gradle.kts +import com.expediagroup.graphql.plugin.gradle.config.GraphQLSerializer +import com.expediagroup.graphql.plugin.gradle.graphql + +plugins { + kotlin("plugin.serialization") version $kotlinVersion +} + +dependencies { + implementation("com.expediagroup", "graphql-kotlin-spring-client", $graphQLKotlinVersion) { + exclude("com.expediagroup", "graphql-kotlin-client-jackson") + } + implementation("com.expediagroup", "graphql-kotlin-client-serialization", $graphQLKotlinVersion) +} + +graphql { + client { + endpoint = "http://localhost:8080/graphql" + packageName = "com.example.generated" + serializer = GraphQLSerializer.KOTLINX + } +} +``` + + + + +```xml + + + + + com.expediagroup + graphql-kotlin-spring-client + ${graphql-kotlin.version} + + + com.expediagroup + graphql-kotlin-client-jackson + + + + + com.expediagroup + graphql-kotlin-client-serialization + ${graphql-kotlin.version} + + + org.jetbrains.kotlinx + kotlinx-serialization-json + ${kotlinx-serialization.version} + + + + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + 1.8 + + kotlinx-serialization + + + + + compile + + compile + + + + test-compile + + test-compile + + + + + + org.jetbrains.kotlin + kotlin-maven-serialization + ${kotlin.version} + + + + + com.expediagroup + graphql-kotlin-maven-plugin + ${graphql-kotlin.version} + + + + introspect-schema + generate-client + + + http://localhost:8080/graphql + com.example.generated + KOTLINX + + + + + + + +``` + + + + +By default, `ServiceLoader` mechanism will load the first available GraphQL client serializer from the classpath. We can +also explicitly specify serializer during client construction + +```kotlin +val client = GraphQLWebClient( + url = "http://localhost:8080/graphql" + serializer = GraphQLClientKotlinxSerializer() +) +``` + +## GraphQL Kotlin Ktor Client + +### Using Kotlinx Serialization + +`kotlinx.serialization` is the default serializer used by the GraphQL Kotlin Ktor Client. Build plugins default to use +`Jackson` so we have to explicitly configure the tasks/mojos to use appropriate serializer. + + + + + +```kotlin +// build.gradle.kts +import com.expediagroup.graphql.plugin.gradle.config.GraphQLSerializer +import com.expediagroup.graphql.plugin.gradle.graphql + +plugins { + kotlin("plugin.serialization") version $kotlinVersion +} + +dependencies { + implementation("com.expediagroup", "graphql-kotlin-ktor-client", $graphQLKotlinVersion) { +} + +graphql { + client { + endpoint = "http://localhost:8080/graphql" + packageName = "com.example.generated" + serializer = GraphQLSerializer.KOTLINX + } +} +``` + + + + +```xml + + + + + com.expediagroup + graphql-kotlin-ktor-client + ${graphql-kotlin.version} + + + org.jetbrains.kotlinx + kotlinx-serialization-json + ${kotlinx-serialization.version} + + + + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + 1.8 + + kotlinx-serialization + + + + + compile + + compile + + + + test-compile + + test-compile + + + + + + org.jetbrains.kotlin + kotlin-maven-serialization + ${kotlin.version} + + + + + com.expediagroup + graphql-kotlin-maven-plugin + ${graphql-kotlin.version} + + + + introspect-schema + generate-client + + + http://localhost:8080/graphql + com.example.generated + KOTLINX + + + + + + + +``` + + + + +By default, `ServiceLoader` mechanism will load the first available GraphQL client serializer from the classpath. + +```kotlin +val client = GraphQLKtorClient( + url = URL("http://localhost:8080/graphql") + serializer = GraphQLClientKotlinxSerializer() +) +``` + +### Using Jackson + +In order to use `Jackson` we need to + +* add dependency on `graphql-kotlin-client-jackson` +* explicitly specify the target serializer during client construction OR exclude `graphql-kotlin-client-serialization` dependency + + + + + +```kotlin +// build.gradle.kts +import com.expediagroup.graphql.plugin.gradle.graphql + +dependencies { + implementation("com.expediagroup", "graphql-kotlin-ktor-client", $graphQLKotlinVersion) { + exclude("com.expediagroup", "graphql-kotlin-client-serialization") + } + implementation("com.expediagroup", "graphql-kotlin-client-jackson", $graphQLKotlinVersion) +} + +graphql { + client { + endpoint = "http://localhost:8080/graphql" + packageName = "com.example.generated" + } +} +``` + + + + +```xml + + + + + com.expediagroup + graphql-kotlin-ktor-client + ${graphql-kotlin.version} + + + com.expediagroup + graphql-kotlin-client-serialization + + + + + com.expediagroup + graphql-kotlin-client-jackson + ${graphql-kotlin.version} + + + + + + + + com.expediagroup + graphql-kotlin-maven-plugin + ${graphql-kotlin.version} + + + + introspect-schema + generate-client + + + http://localhost:8080/graphql + com.example.generated + + + + + + + +``` + + + + +By default, `ServiceLoader` mechanism will load the first available GraphQL client serializer from the classpath. We can +also explicitly specify serializer during client construction + +```kotlin +val client = GraphQLKtorClient( + url = URL("http://localhost:8080/graphql") + serializer = GraphQLClientJacksonSerializer() +) +``` diff --git a/website/versioned_docs/version-7.x.x/examples.md b/website/versioned_docs/version-7.x.x/examples.md new file mode 100644 index 0000000000..d6d2c55fce --- /dev/null +++ b/website/versioned_docs/version-7.x.x/examples.md @@ -0,0 +1,52 @@ +--- +id: examples +title: Examples +--- +A collection of example apps that use graphql-kotlin libraries to test and demonstrate usages can be found in the [examples module](https://github.com/ExpediaGroup/graphql-kotlin/tree/master/examples). + +## Client Example + +A `graphql-kotlin-client` can be generated by using the provided Maven or Gradle. Example integration using Maven and +Gradle plugins can be found under the [examples/client](https://github.com/ExpediaGroup/graphql-kotlin/tree/master/examples/client) +folder. + +## Federation Example + +There is also an example of [Apollo Federation](https://www.apollographql.com/docs/apollo-server/federation/introduction/) +with two Spring Boot apps using `graphql-kotlin-federation` and an Apollo Gateway app in Nodejs that exposes a single +federated schema in [examples/federation](https://github.com/ExpediaGroup/graphql-kotlin/tree/master/examples/federation) +project. Please refer to the README files for details on how to run each application. + +## Server Examples + +Example integrations of `graphql-kotlin-schema-generator` with number of popular application frameworks can be found under +[examples/server](https://github.com/ExpediaGroup/graphql-kotlin/tree/master/examples/server) folder. + +These examples also demonstrates how to include [`DataLoaders`](https://github.com/graphql-java/java-dataloader) in your query execution. + +### Ktor Server Example + +[Ktor](http://ktor.io/) is an asynchronous framework for creating microservices, web applications, and more. Example +integration can be found at [examples/server/ktor-server](https://github.com/ExpediaGroup/graphql-kotlin/tree/master/examples/server/ktor-server) + +### Spring Server Example + +One way to run a GraphQL server is with [Spring Boot](https://github.com/spring-projects/spring-boot). A sample Spring +Boot app that uses [Spring +Webflux](https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html) together with +`graphql-kotlin-schema-generator` and [graphiql](https://github.com/graphql/graphiql) is provided as +a [examples/server/spring-server](https://github.com/ExpediaGroup/graphql-kotlin/tree/master/examples/server/spring-server). +All the examples used in this documentation should be available in this sample app. + +In order to run it you can run +[Application.kt](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/examples/spring/src/main/kotlin/com/expediagroup/graphql/examples/Application.kt) +directly from your IDE. Alternatively you can also use the Spring Boot plugin from the command line. + +```shell script + +./gradlew bootRun + +``` + +Once the app has started you can explore the example schema by opening Playground endpoint at +http:. diff --git a/website/versioned_docs/version-7.x.x/framework-comparison.md b/website/versioned_docs/version-7.x.x/framework-comparison.md new file mode 100644 index 0000000000..11a42bd21a --- /dev/null +++ b/website/versioned_docs/version-7.x.x/framework-comparison.md @@ -0,0 +1,168 @@ +--- +id: framework-comparison +title: GraphQL Frameworks Comparison +--- + +## GraphQL Java +[graphql-java](https://graphql-java.com/) is one of the most popular JVM based GraphQL implemenations. GraphQL Kotlin is +built on top of `grahpql-java` as it can be easily extended with additional functionality and this implementation +has been used and tested by many users. + +### GraphQL Java Schema + +The most common way to create the schema in `graphql-java` is to first manually write the SDL file: + +```graphql +schema { + query: Query +} + +type Query { + bookById(id: ID): Book +} + +type Book { + id: ID! + name: String! + pageCount: Int! + author: Author +} + +type Author { + id: ID! + firstName: String! + lastName: String! +} +``` + +Then write the runtime code that matches this schema to build the `GraphQLSchema` object. + +```kotlin +// Internal DB class, not schema class +class Book( + val id: ID, + val name: String, + val totalPages: Int, // This needs to be renamed to pageCount + val authorId: ID // This is not in the schema +) + +// Internal DB class, not schema class +class Author( + val id: ID, + val firstName: String, + val lastName: String +) + +class GraphQLDataFetchers { + private val books: List = booksFromDB() + private val authors: List = authorsFromDB() + + fun getBookByIdDataFetcher() = DataFetcher { dataFetchingEnvironment -> + val bookId: String = dataFetchingEnvironment.getArgument("id") + return books.firstOrNull { it.id == bookId } + } + + fun getAuthorDataFetcher() = DataFetcher { dataFetchingEnvironment -> + val book: Book = dataFetchingEnvironment.getSource() as Book + return authors.firstOrNull { it.id == book.authorId } + } + + fun getPageCountDataFetcher() = DataFetcher { dataFetchingEnvironment -> + val book: Book = dataFetchingEnvironment.getSource() as Book + return book.totalPages + } +} + +val schemaParser = SchemaParser() +val schemaGenerator = SchemaGenerator() +val schemaFile = loadSchema("schema.graphqls") +val typeRegistry = schemaParser.parse(schemaFile) +val graphQLDataFetchers = GraphQLDataFetchers() + +val runtimeWiring = RuntimeWiring.newRuntimeWiring() + .type( + newTypeWiring("Query") + .dataFetcher("bookById", graphQLDataFetchers.getBookByIdDataFetcher()) + ) + .type( + newTypeWiring("Book") + .dataFetcher("author", graphQLDataFetchers.getAuthorDataFetcher()) + .dataFetcher("pageCount", graphQLDataFetchers.getPageCountDataFetcher()) + ) + .build() + +// Combine the types and runtime code together to make a schema +val graphQLSchema: GraphQLSchema = schemaGenerator.makeExecutableSchema(typeDefinitionRegistry, runtimeWiring) +``` + +This means that there are two sources of truth for your schema and changes in either have to be reflected in both locations. +As your schema scales to hundreds of types and many different resolvers, it can get more difficult to track what code needs to be changed if you want to add a new field, +deprecate or delete an existing one, or fix a bug in the resolver code. + +These errors will hopefully be caught by your build or automated tests, but it is another layer your have to be worried about when creating your API. + +### GraphQL Kotlin Schema + +`graphql-kotlin-schema-generator` aims to simplify this process by using Kotlin reflection to generate the schema for you. +All you need to do is write your schema code in a Kotlin class with public functions or properties. + +```kotlin +private val books: List = booksFromDB() +private val authors: List = authorsFromDB() + +class Query { + fun bookById(id: ID): Book? = books.find { it.id == id } +} + +class Book( + val id: ID, + val name: String, + private val totalPages: Int, + private val authorId: ID +) { + fun author(): Author? = authors.find { it.id == authorId } + fun pageCount(): Int = totalPages +} + +class Author( + val id: ID, + val firstName: String, + val lastName: String +) + +val config = SchemaGeneratorConfig(supportedPackages = "com.example") +val queries = listOf(TopLevelObject(Query())) +val schema: GraphQLSchema = toSchema(config, queries) +``` + +This makes changes in code directly reflect to your schema and you can still produce the `GraphQLSchema` to print and export an SDL file. + + +## DGS +[DGS](https://netflix.github.io/dgs/) is a GraphQL server framework for Spring Boot. It works with both Java and Kotlin. +DGS is also built on top of `graphql-java` and implements many similar features to `graphql-kotlin` and [graphql-java-kickstart/graphql-spring-boot](https://github.com/graphql-java-kickstart/graphql-spring-boot). + +* Auto-configuration of server routes and request handling +* Auto-wiring of data fetchers (resolvers) to the `GraphQLSchema` +* Apollo Federation support +* Subscriptions support +* Client schema-code generation + +While both libraries do very similar things, there are some minor differences which may serve different usecases better. +As with open source library, you can compare and use the right tool for the job. + +### Extra Features of DGS + +* Support for a SDL-First (Schema-First) approach +* Ability to autogenerate code stubs from the schema +* Includes [JsonPath](https://github.com/json-path/JsonPath) testing library +* Build on top of Spring MVC + +### Extra Features of graphql-kotlin + +* Supports code-first approach (generates schema from source code - does not require duplicate implementation of data fetchers, schema classes, and SDL files) +* Abstract server logic can be used in any framework, e.g. Ktor +* Reference server implementation build on top of [Spring Webflux](https://spring.io/reactive) for a reactive server stack +* Simple nesting of data fetchers +* Client code generation for Ktor and Spring +* Client plugin support for both Maven and Gradle diff --git a/website/versioned_docs/version-7.x.x/getting-started.mdx b/website/versioned_docs/version-7.x.x/getting-started.mdx new file mode 100644 index 0000000000..9a5643db03 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/getting-started.mdx @@ -0,0 +1,82 @@ +--- +id: getting-started +title: Getting Started +slug: / +--- + + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +GraphQL Kotlin is a collection of libraries, built on top of [graphql-java](https://www.graphql-java.com/), that simplify running GraphQL clients and servers in Kotlin. + +## Installation + +Using a JVM dependency manager, link any `graphql-kotlin-*` library to your project. + + + + + +```kotlin +implementation("com.expediagroup", "graphql-kotlin-spring-server", latestVersion) +``` + + + + +```xml + + com.expediagroup + graphql-kotlin-spring-server + ${latestVersion} + +``` + + + + +## Generating a Schema + +You can use `graphql-kotlin-schema-generator` to generate a schema from Kotlin code and expose it with any server library. + +See the docs in [Schema Generator Getting Started](./schema-generator/schema-generator-getting-started.mdx). + +### Apollo Federation + +Using `graphql-kotlin-federation`, you can generate an [Apollo Federation](https://www.apollographql.com/docs/apollo-server/federation/federation-spec/) compliant schema. + +See the docs in [Apollo Federation](./schema-generator/federation/apollo-federation.mdx). + +## Running a Server + +`graphql-kotlin-server` is a combination of the schema generator, federation, and server libraries. If you are looking to run a GraphQL server, this is the place to start. + +See the docs in [GraphQL Kotlin Server](./server/graphql-server.md). + +## Creating a Client + +`graphql-kotlin-plugins` can be used to generate a `graphql-kotlin-client` from an existing schema that is easy to use and type-safe. + +See the docs in [Client Overview](./client/client-overview.mdx). + +## Examples + +The `examples` module is a collection of working code and examples on how to use all of the `graphql-kotlin` modules. + +See the [example docs](./examples.md) for more info. + +## Blogs and Videos + +You can find more posts and recorded conference talks on GraphQL and `graphql-kotlin` on our [Blogs and Videos](./blogs-and-videos.md) page. + +## Additional resources + +- [GraphQL](https://graphql.org/) +- [graphql-java](https://www.graphql-java.com/) diff --git a/website/versioned_docs/version-7.x.x/plugins/gradle-plugin-tasks.mdx b/website/versioned_docs/version-7.x.x/plugins/gradle-plugin-tasks.mdx new file mode 100644 index 0000000000..a92e14cee2 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/plugins/gradle-plugin-tasks.mdx @@ -0,0 +1,450 @@ +--- +id: gradle-plugin-tasks +title: Gradle Plugin Tasks +sidebar_label: Tasks Overiew +--- + + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +GraphQL Kotlin Gradle Plugin provides functionality to generate a lightweight GraphQL HTTP client and generate GraphQL +schema directly from your source code. + +:::info +This plugin is dependent on Kotlin compiler plugin as it generates Kotlin source code that needs to be compiled. +::: + +## Usage + +`graphql-kotlin-gradle-plugin` is published on Gradle [Plugin Portal](https://plugins.gradle.org/plugin/com.expediagroup.graphql). +In order to execute any of the provided tasks you need to first apply the plugin on your project. + + + + + +Using plugins DSL syntax + +```kotlin +plugins { + id("com.expediagroup.graphql") version $graphQLKotlinVersion +} +``` + +Or by using legacy plugin application + +```kotlin +buildscript { + repositories { + maven { + url = uri("https://plugins.gradle.org/m2/") + } + } + dependencies { + classpath("com.expediagroup:graphql-kotlin-gradle-plugin:$graphQLKotlinVersion") + } +} + +apply(plugin = "com.expediagroup.graphql") +``` + + + + +Using plugins DSL syntax + +```groovy +// build.gradle +plugins { + id 'com.expediagroup.graphql' version $graphQLKotlinVersion +} +``` + +Or by using legacy plugin application + +```groovy +// build.gradle +buildscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath "com.expediagroup:graphql-kotlin-gradle-plugin:$graphQLKotlinVersion" + } +} + +apply plugin: "com.expediagroup.graphql" +``` + + + + +## Extension + +GraphQL Kotlin Gradle Plugin uses an extension on the project named `graphql` of type +[GraphQLPluginExtension](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/plugins/graphql-kotlin-gradle-plugin/src/main/kotlin/com/expediagroup/graphql/plugin/gradle/GraphQLPluginExtension.kt). +This extension can be used to configure global options instead of explicitly configuring individual tasks. Once extension +is configured, it will automatically download SDL/run introspection to generate GraphQL schema and subsequently generate +all GraphQL clients. GraphQL Extension should be used by default, except for cases where you need to only run individual +tasks. + + + + + +```kotlin +// build.gradle.kts +import com.expediagroup.graphql.plugin.gradle.config.GraphQLScalar +import com.expediagroup.graphql.plugin.gradle.config.GraphQLSerializer +import com.expediagroup.graphql.plugin.gradle.graphql + +graphql { + client { + // Boolean flag indicating whether or not selection of deprecated fields is allowed. + allowDeprecatedFields = false + // List of custom GraphQL scalar to converter mapping containing information about corresponding Java type and converter that should be used to serialize/deserialize values. + customScalars = listOf(GraphQLScalar("UUID", "java.util.UUID", "com.example.UUIDScalarConverter")) + // GraphQL server endpoint that will be used to for running introspection queries. Alternatively you can download schema directly from `sdlEndpoint` or specify local `schemaFile`. + endpoint = "http://localhost:8080/graphql" + // Optional HTTP headers to be specified on an introspection query or SDL request. + headers = mapOf("X-Custom-Header" to "Custom-Header-Value") + // Target package name to be used for generated classes. + packageName = "com.example.generated" + // Custom directory containing query files, defaults to src/main/resources + queryFileDirectory = "${project.projectDir}/src/main/resources/queries" + // Optional list of query files to be processed, takes precedence over queryFileDirectory + queryFiles = listOf(file("${project.projectDir}/src/main/resources/queries/MyQuery.graphql")) + // GraphQL schema file. Can be used instead of `endpoint` or `sdlEndpoint`. + schemaFile = file("${project.projectDir}/src/main/resources/myLocalSchema.graphql") + // GraphQL server SDL endpoint that will be used to download schema. Alternatively you can run introspection query against `endpoint` or specify local `schemaFile`. + sdlEndpoint = "http://localhost:8080/sdl" + // JSON serializer that will be used to generate the data classes. + serializer = GraphQLSerializer.JACKSON + // Timeout configuration for introspection query/downloading SDL + timeout { + // Connect timeout in milliseconds + connect = 5_000 + // Read timeout in milliseconds + read = 15_000 + } + // Override options that GraphQL Java uses when parsing GraphQL queries and schema definition language documents. + parserOptions { + // Override the maximum number of tokens read to prevent processing extremely large queries. + maxTokens = 15000 + // Override the maximum number of whitespace tokens read to prevent processing extremely large queries. + maxWhitespaceTokens = 200000 + // Modify the maximum number of characters in a document to prevent malicious documents consuming CPU + maxCharacters = 1048576 + // Modify the maximum grammar rule depth to negate malicious documents that can cause stack overflows + maxRuleDepth = 500 + // Single-line comments do not have any semantic meaning in GraphQL source documents and can be ignored + captureLineComments = false + // Memory usage is significantly reduced by not capturing ignored characters, especially in SDL parsing. + captureIgnoredChars = false + // Memory usage is reduced by not setting SourceLocations on AST nodes, especially in SDL parsing. + captureSourceLocation = true + } + // Opt-in flag to wrap nullable arguments in OptionalInput that distinguish between null and undefined value. + useOptionalInputWrapper = false + } + graalVm { + // List of supported packages that can contain GraphQL schema type definitions + packages = listOf("com.example") + // Application main class name + mainClassName = "com.example.ApplicationKt" + } + schema { + // List of supported packages that can contain GraphQL schema type definitions + packages = listOf("com.example") + } +} +``` + + + + +```groovy +// build.gradle +import com.expediagroup.graphql.plugin.gradle.config.GraphQLScalar +import com.expediagroup.graphql.plugin.gradle.config.GraphQLSerializer + +graphql { + client { + // Boolean flag indicating whether or not selection of deprecated fields is allowed. + allowDeprecatedFields = false + // List of custom GraphQL scalar to converter mapping containing information about corresponding Java type and converter that should be used to serialize/deserialize values. + customScalars = [new GraphQLScalar("UUID", "java.util.UUID", "com.example.UUIDScalarConverter")] + // GraphQL server endpoint that will be used to for running introspection queries. Alternatively you can download schema directly from `sdlEndpoint` or specify local `schemaFile`. + endpoint = "http://localhost:8080/graphql" + // Optional HTTP headers to be specified on an introspection query or SDL request. + headers = ["X-Custom-Header" : "My-Custom-Header-Value"] + // Target package name to be used for generated classes. + packageName = "com.example.generated" + // Custom directory containing query files, defaults to src/main/resources + queryFileDirectory = "${project.projectDir}/src/main/resources/queries" + // Optional list of query files to be processed, takes precedence over queryFileDirectory + queryFiles = [file("${project.projectDir}/src/main/resources/queries/MyQuery.graphql")] + // GraphQL schema file. Can be used instead of `endpoint` or `sdlEndpoint`. + schemaFile = file("${project.projectDir}/src/main/resources/myLocalSchema.graphql") + // GraphQL server SDL endpoint that will be used to download schema. Alternatively you can run introspection query against `endpoint` or specify local `schemaFile`. + sdlEndpoint = "http://localhost:8080/sdl" + // JSON serializer that will be used to generate the data classes. + serializer = GraphQLSerializer.JACKSON + // Timeout configuration for introspection query/downloading SDL + timeout { t -> + // Connect timeout in milliseconds + t.connect = 5000 + t.read = 15000 + } + // Override options that GraphQL Java uses when parsing GraphQL queries and schema definition language documents. + parserOptions { options -> + // Override the maximum number of tokens read to prevent processing extremely large queries. + options.maxTokens = 15000 + // Override the maximum number of whitespace tokens read to prevent processing extremely large queries. + options.maxWhitespaceTokens = 200000 + // Modify the maximum number of characters in a document to prevent malicious documents consuming CPU + options.maxCharacters = 1048576 + // Modify the maximum grammar rule depth to negate malicious documents that can cause stack overflows + options.maxRuleDepth = 500 + // Memory usage is significantly reduced by not capturing ignored characters, especially in SDL parsing. + options.captureIgnoredChars = false + // Memory usage is reduced by not setting SourceLocations on AST nodes, especially in SDL parsing. + options.captureSourceLocation = true + // Single-line comments do not have any semantic meaning in GraphQL source documents and can be ignored + options.captureLineComments = true + } + // Opt-in flag to wrap nullable arguments in OptionalInput that distinguish between null and undefined value. + useOptionalInputWrapper = false + } + graalVm { + // List of supported packages that can contain GraphQL schema type definitions + packages = ["com.example"] + // Application main class name + mainClassName = "com.example.ApplicationKt" + } + schema { + packages = ["com.example"] + } +} +``` + + + + +## Tasks + +By default, `graphql-kotlin-gradle-plugin` lazily registers all its tasks which means that while they are known to the build, +they are not created nor executed until something in the build needs the instantiated object (e.g. adding explicit dependency +on those tasks or explicitly creating them). **Configuring plugin through the `graphql` extension will automatically create +all the corresponding tasks**. + +All `graphql-kotlin-gradle-plugin` tasks are grouped together under `GraphQL` task group and their names are prefixed with +`graphql`. You can find detailed information about GraphQL kotlin tasks by running `gradle help --task `. + +```shell +$ gradle tasks --group graphql + +GraphQL tasks +------------- +graphqlDownloadSDL - Download schema in SDL format from target endpoint. +graphqlGenerateClient - Generate HTTP client from the specified GraphQL queries. +graphqlGenerateSDL - Generate GraphQL schema in SDL format. +graphqlGenerateTestClient - Generate HTTP test client from the specified GraphQL queries. +graphqLGraalVmMetadata - Generate GraalVM reflect metadata for GraphQL Kotlin servers. +graphqlIntrospectSchema - Run introspection query against target GraphQL endpoint and save schema locally.--> +``` + +### graphqlDownloadSDL + +Task that attempts to download GraphQL schema in SDL format from the specified `endpoint` and saves the underlying +schema file as `schema.graphql` under build directory. In general, this task provides limited functionality by itself +and could be used as an alternative to `graphqlIntrospectSchema` to generate input for the subsequent +`graphqlGenerateClient` task. + +:::info +This task will always be `UP-TO-DATE` and in order to trigger the re-download of an SDL you need to force rerun it by +specifying `--rerun-tasks` option or by executing `clean` task. +::: + +**Properties** + +| Property | Type | Required | Description | +| ---------------------- | ------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `endpoint` | String | yes | Target GraphQL server SDL endpoint that will be used to download schema.
**Command line property is**: `endpoint`. | +| `headers` | `Map` | | Optional HTTP headers to be specified on a SDL request. | +| `outputFile` | File | | Target GraphQL schema file to be generated.
**Default value is:** `${project.buildDir}/schema.graphql` | +| `timeoutConfig` | TimeoutConfig | | Timeout configuration (in milliseconds) to download schema from SDL endpoint before we cancel the request.
**Default value are:**
connect timeout = 5_000
read timeout = 15_000.
| + +### graphqlGenerateClient + +Task that generates GraphQL Kotlin client and corresponding data classes based on the provided GraphQL queries that are +evaluated against target Graphql schema. Individual clients with their specific data models are generated for each query +file and are placed under specified `packageName`. When this task is added to the project, either through explicit configuration +or through the `graphql` extension, it will automatically configure itself as a dependency of a `compileKotlin` task and +resulting generated code will be automatically added to the project main source set. + +**Properties** + +| Property | Type | Required | Description | +|---------------------------|-----------------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `allowDeprecatedFields` | Boolean | | Boolean flag indicating whether selection of deprecated fields is allowed or not.
**Default value is:** `false`.
**Command line property is**: `allowDeprecatedFields`. | +| `customScalars` | `List` | | List of custom GraphQL scalar to converter mappings containing information about corresponding Java type and converter that should be used to serialize/deserialize values. | +| `packageName` | String | yes | Target package name for generated code.
**Command line property is**: `packageName`. | +| `parserOptions` | GraphQLParserOptions | | Configures the settings used when parsing GraphQL queries and schema definition language documents. | +| `queryFiles` | FileCollection | | List of query files to be processed. Instead of a list of files to be processed you can specify `queryFileDirectory` directory instead. If this property is specified it will take precedence over the corresponding directory property. | +| `queryFileDirectory` | Directory | | Directory file containing GraphQL queries. Instead of specifying a directory you can also specify list of query file by using `queryFiles` property instead.
**Default value is:** `src/main/resources`. | +| `schemaFile` | File | yes | GraphQL schema file that will be used to generate client code. | +| `serializer` | GraphQLSerializer | | JSON serializer that will be used to generate the data classes.
**Default value is:** `GraphQLSerializer.JACKSON`. | +| `useOptionalInputWrapper` | Boolean | | Boolean opt-in flag to wrap nullable arguments in `OptionalInput` that distinguish between `null` and undefined/omitted value.
**Default value is:** `false`.
**Command line property is**: `useOptionalInputWrapper` | + +By default, this task will generate Jackson compatible data models. See [client serialization documentation](../client/client-serialization.mdx) +for details on how to update this process to use `kotlinx.serialization` instead. + +**Parameter Details** + + * *parserOptions* - Configure options for parsing GraphQL queries and schema definition language documents. Settings here override the defaults set by GraphQL Java. + + ```kotlin + // Override options that GraphQL Java uses when parsing GraphQL queries and schema definition language documents. + parserOptions { + // Override the maximum number of tokens read to prevent processing extremely large queries. + maxTokens = 15000 + // Override the maximum number of whitespace tokens read to prevent processing extremely large queries. + maxWhitespaceTokens = 200000 + // Modify the maximum number of characters in a document to prevent malicious documents consuming CPU + maxCharacters = 1048576 + // Modify the maximum grammar rule depth to negate malicious documents that can cause stack overflows + maxRuleDepth = 500 + // Memory usage is significantly reduced by not capturing ignored characters, especially in SDL parsing. + captureIgnoredChars = false + // Memory usage is reduced by not setting SourceLocations on AST nodes, especially in SDL parsing. + captureSourceLocation = true + // Single-line comments do not have any semantic meaning in GraphQL source documents and can be ignored + captureLineComments = true + } + ``` + +### graphqlGenerateSDL + +Task that generates GraphQL schema in SDL format from your source code using reflections. Utilizes `graphql-kotlin-schema-generator` +to generate the schema from classes implementing `graphql-kotlin-server` marker `Query`, `Mutation` and `Subscription` interfaces. +In order to limit the amount of packages to scan, this task requires users to provide a list of `packages` that can contain +GraphQL types. + +**Properties** + +| Property | Type | Required | Description | +| -------- | ---- | -------- | ----------- | +| `packages` | `List` | yes | List of supported packages that can be scanned to generate SDL. | +| `schemaFile` | File | | Target GraphQL schema file to be generated.
**Default value is:** `${project.buildDir}/schema.graphql` | + +By default, this task will attempt to generate the schema using `NoopSchemaGeneratorHooks`. If you need to customize your +schema generation process, you will need to provide your custom instance of `SchemaGeneratorHooksProvider` service provider. +Service provider can be provided as part of your project, included in one of your project dependencies or through explicitly +provided artifact to the `graphqlSDL` configuration. + +```kotlin +dependencies { + graphqlSDL("com.expediagroup:graphql-kotlin-federated-hooks-provider:$graphQLKotlinVersion") +} +``` + +### graphqlGenerateTestClient + +Task that generates GraphQL Kotlin test client and corresponding data classes based on the provided GraphQL queries that are +evaluated against target Graphql schema. Individual test clients with their specific data models are generated for each query +file and are placed under specified `packageName`. When this task is added to the project it will automatically configure +itself as a dependency of a `compileTestKotlin` task and resulting generated code will be automatically added to the project +test source set. + +**Properties** + +| Property | Type | Required | Description | +|---------------------------|-----------------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `allowDeprecatedFields` | Boolean | | Boolean flag indicating whether selection of deprecated fields is allowed or not.
**Default value is:** `false`.
**Command line property is**: `allowDeprecatedFields`. | +| `customScalars` | `List` | | List of custom GraphQL scalar to converter mappings containing information about corresponding Java type and converter that should be used to serialize/deserialize values. | +| `packageName` | String | yes | Target package name for generated code.
**Command line property is**: `packageName`. | +| `parserOptions` | GraphQLParserOptions | | Configures the settings used when parsing GraphQL queries and schema definition language documents. | +| `queryFiles` | FileCollection | | List of query files to be processed. Instead of a list of files to be processed you can specify `queryFileDirectory` directory instead. If this property is specified it will take precedence over the corresponding directory property. | +| `queryFileDirectory` | Directory | | Directory file containing GraphQL queries. Instead of specifying a directory you can also specify list of query file by using `queryFiles` property instead.
**Default value is:** `src/test/resources`. | +| `schemaFile` | File | yes | GraphQL schema file that will be used to generate client code. | +| `serializer` | GraphQLSerializer | | JSON serializer that will be used to generate the data classes.
**Default value is:** `GraphQLSerializer.JACKSON`. | +| `useOptionalInputWrapper` | Boolean | | Boolean opt-in flag to wrap nullable arguments in `OptionalInput` that distinguish between `null` and undefined/omitted value.
**Default value is:** `false`.
**Command line property is**: `useOptionalInputWrapper` | + +By default, this task will generate Jackson compatible data models. See [client serialization documentation](../client/client-serialization.mdx) +for details on how to update this process to use `kotlinx.serialization` instead. + +**Parameter Details** + + * *parserOptions* - Configure options for parsing GraphQL queries and schema definition language documents. Settings here override the defaults set by GraphQL Java. + + ```kotlin + // Override options that GraphQL Java uses when parsing GraphQL queries and schema definition language documents. + parserOptions { + // Override the maximum number of tokens read to prevent processing extremely large queries. + maxTokens = 15000 + // Override the maximum number of whitespace tokens read to prevent processing extremely large queries. + maxWhitespaceTokens = 200000 + // Modify the maximum number of characters in a document to prevent malicious documents consuming CPU + maxCharacters = 1048576 + // Modify the maximum grammar rule depth to negate malicious documents that can cause stack overflows + maxRuleDepth = 500 + // Memory usage is significantly reduced by not capturing ignored characters, especially in SDL parsing. + captureIgnoredChars = false + // Memory usage is reduced by not setting SourceLocations on AST nodes, especially in SDL parsing. + captureSourceLocation = true + // Single-line comments do not have any semantic meaning in GraphQL source documents and can be ignored + captureLineComments = true + } + ``` + +### graphqLGraalVmMetadata + +Task that generates [GraalVM Reachability Metadata](https://www.graalvm.org/latest/reference-manual/native-image/metadata/) +for `graphql-kotlin` servers. Based on the GraphQL schema it will generate `native-image.properties`, `reflect-config.json` +and `resource-config.json` metadata files under `build/generated/graphqlGraalVmResources/META-INF/native-image///graphql` + +Task will be automatically applied if the project applies [GraalVM Native Plugin](https://graalvm.github.io/native-build-tools/latest/gradle-plugin.html). + +**Properties** + +| Property | Type | Required | Description | +| -------- |------| -------- |-------------| +| `packages` | `List` | yes | List of supported packages that can be can contain GraphQL schema. | +| `mainClassName` | String | | Application main class name. | + +### graphqlIntrospectSchema + +Task that executes GraphQL introspection query against specified `endpoint` and saves the underlying schema file as +`schema.graphql` under build directory. In general, this task provides limited functionality by itself and instead +should be used to generate input for the subsequent `graphqlGenerateClient` task. + +:::info +This task will always be `UP-TO-DATE` and in order to trigger the re-running of the introspection query you need to force +rerun it by specifying `--rerun-tasks` option or by executing `clean` task. +::: + +**Properties** + +| Property | Type | Required | Description | +| -------- | ---- | -------- | ----------- | +| `endpoint` | String | yes | Target GraphQL server endpoint that will be used to execute introspection queries.
**Command line property is**: `endpoint`. | +| `headers` | `Map` | | Optional HTTP headers to be specified on an introspection query. | +| `outputFile` | File | | Target GraphQL schema file to be generated.
**Default value is:** `${project.buildDir}/schema.graphql` | +| `streamResponse` | Boolean | | Boolean property to indicate whether to use streamed (chunked) responses.
**Default value is:** true. | +| `timeoutConfig` | TimeoutConfig | | Timeout configuration (in milliseconds) to download schema from SDL endpoint before we cancel the request.
**Default value are:**
connect timeout = 5_000
read timeout = 15_000.
| diff --git a/website/versioned_docs/version-7.x.x/plugins/gradle-plugin-usage-client.mdx b/website/versioned_docs/version-7.x.x/plugins/gradle-plugin-usage-client.mdx new file mode 100644 index 0000000000..8e33db432e --- /dev/null +++ b/website/versioned_docs/version-7.x.x/plugins/gradle-plugin-usage-client.mdx @@ -0,0 +1,654 @@ +--- +id: gradle-plugin-usage-client +title: Gradle Plugin Client Usage +sidebar_label: Generating Client +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +GraphQL Kotlin plugins can be used to generate a lightweight type-safe GraphQL HTTP clients. See examples below for more +information about the client generating tasks. + +## Downloading Schema SDL + +GraphQL endpoints are often public and as such many servers might disable introspection queries in production environment. +Since GraphQL schema is needed to generate type safe clients, as alternative GraphQL servers might expose private +endpoints (e.g. accessible only from within network, etc) that could be used to download schema in Schema Definition +Language (SDL) directly. `graphqlDownloadSDL` task requires target GraphQL server `endpoint` to be specified and can +be executed directly from the command line by explicitly passing `endpoint` parameter + +```shell script +$ gradle graphqlDownloadSDL --endpoint="http://localhost:8080/sdl" +``` + +Task can also be explicitly configured in your Gradle build file + + + + + +```kotlin +// build.gradle.kts +import com.expediagroup.graphql.plugin.gradle.tasks.GraphQLDownloadSDLTask + +val graphqlDownloadSDL by tasks.getting(GraphQLDownloadSDLTask::class) { + endpoint.set("http://localhost:8080/sdl") +} +``` + + + + +```groovy +//build.gradle +graphqlDownloadSDL { + endpoint = "http://localhost:8080/sdl" +} +``` + + + + +:::info +This task does not automatically configure itself to be part of your build lifecycle. You will need to explicitly +invoke it OR configure it as a dependency of some other task. +::: + +## Introspecting Schema + +Introspection task requires target GraphQL server `endpoint` to be specified. Task can be executed directly from the +command line by explicitly passing endpoint parameter + +```shell script +$ gradle graphqlIntrospectSchema --endpoint="http://localhost:8080/graphql" +``` + +Task can also be explicitly configured in your Gradle build file + + + + + +```kotlin +// build.gradle.kts +import com.expediagroup.graphql.plugin.gradle.tasks.GraphQLGenerateClientTask + +val graphqlIntrospectSchema by tasks.getting(GraphQLIntrospectSchemaTask::class) { + endpoint.set("http://localhost:8080/graphql") +} +``` + + + + +```groovy +//build.gradle +graphqlIntrospectSchema { + endpoint = "http://localhost:8080/graphql" +} +``` + + + + +:::info +This task does not automatically configure itself to be part of your build lifecycle. You will need to explicitly +invoke it OR configure it as a dependency of some other task. +::: + +## Generating Client + +GraphQL Kotlin client code is generated based on the provided queries that will be executed against target GraphQL `schemaFile`. +Separate class is generated for each provided GraphQL query and are saved under specified `packageName`. + + + + + +```kotlin +// build.gradle.kts +import com.expediagroup.graphql.plugin.gradle.tasks.GraphQLGenerateClientTask + +val graphqlGenerateClient by tasks.getting(GraphQLGenerateClientTask::class) { + packageName.set("com.example.generated") + schemaFile.set(file("${project.projectDir}/mySchema.graphql")) +} +``` + + + + +```groovy +//build.gradle +graphqlGenerateClient { + packageName = "com.example.generated" + schemaFile = file("${project.projectDir}/mySchema.graphql") +} +``` + + + + +This will process all GraphQL files located under `src/main/resources` and generate corresponding GraphQL Kotlin client +data models. Generated classes will be automatically added to the project compile sources. + +## Generating Client with Custom Scalars + +By default, all custom GraphQL scalars will be serialized as Strings. You can override this default behavior by specifying +custom [scalar converter](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/clients/graphql-kotlin-client/src/main/kotlin/com/expediagroup/graphql/client/converter/ScalarConverter.kt). + +For example given following custom scalar in our GraphQL schema + +```graphql +scalar UUID +``` + +We can create a custom converter to automatically convert this custom scalar to `java.util.UUID` + +```kotlin +package com.example + +import com.expediagroup.graphql.client.converter.ScalarConverter +import java.util.UUID + +class UUIDScalarConverter : ScalarConverter { + override fun toScalar(rawValue: Any): UUID = UUID.fromString(rawValue.toString() + override fun toJson(value: UUID): String = value.toString() +} +``` + +Afterwards we need to configure our plugin to use this custom converter + + + + + +```kotlin +// build.gradle.kts +import com.expediagroup.graphql.plugin.gradle.config.GraphQLScalar +import com.expediagroup.graphql.plugin.gradle.tasks.GraphQLGenerateClientTask + +val graphqlGenerateClient by tasks.getting(GraphQLGenerateClientTask::class) { + packageName.set("com.example.generated") + schemaFile.set(file("${project.projectDir}/mySchema.graphql")) + customScalars.add(GraphQLScalar("UUID", "java.util.UUID", "com.example.UUIDScalarConverter")) +} +``` + + + + +```groovy +//build.gradle +import com.expediagroup.graphql.plugin.gradle.config.GraphQLScalar + +graphqlGenerateClient { + packageName = "com.example.generated" + schemaFile = file("${project.projectDir}/mySchema.graphql") + customScalars.add(new GraphQLScalar("UUID", "java.util.UUID", "com.example.UUIDScalarConverter")) +} +``` + + + + +## Generating Client using Kotlinx Serialization + +GraphQL Kotlin plugins default to generate client data models that are compatible with [Jackson](https://github.com/FasterXML/jackson). +We can change this default behavior by explicitly specifying serializer type (in the extension or explicitly in the generate +client task) and configuring `kotlinx.serialization` compiler plugin. See [kotlinx.serialization documentation](https://github.com/Kotlin/kotlinx.serialization) +for details. + + + + + +```kotlin +// build.gradle.kts +import com.expediagroup.graphql.plugin.gradle.config.GraphQLScalar +import com.expediagroup.graphql.plugin.gradle.config.GraphQLSerializer + +plugins { + kotlin("plugin.serialization") version $kotlinVersion +} + +val graphqlGenerateClient by tasks.getting(GraphQLGenerateClientTask::class) { + packageName.set("com.example.generated") + schemaFile.set(file("${project.projectDir}/mySchema.graphql")) + serializer.set(GraphQLSerializer.KOTLINX) +} +``` + + + + +```groovy +//build.gradle +import com.expediagroup.graphql.plugin.gradle.config.GraphQLScalar +import com.expediagroup.graphql.plugin.gradle.config.GraphQLSerializer + +plugins { + id 'org.jetbrains.kotlin.plugin.serialization' version '$kotlinVersion' +} + +graphqlGenerateClient { + packageName = "com.example.generated" + schemaFile = file("${project.projectDir}/mySchema.graphql") + serializer = GraphQLSerializer.KOTLINX +} +``` + + + + +## Generating Client using Classpath Schema + +Client generation tasks require `schemaFile` to be provided. Using Gradle we can configure tasks to use local schema file, +load it from an URI or consume it directly from a classpath. See [Gradle TextResourceFactory](https://docs.gradle.org/current/dsl/org.gradle.api.resources.TextResourceFactory.html) +for additional details. + +If `schema.graphql` file is provided in a `my-lib` JAR we can configure our generate client task as follows + + + + + +```kotlin +// build.gradle.kts +val graphqlGenerateClient by tasks.getting(GraphQLGenerateClientTask::class) { + packageName.set("com.example.generated") + val archive = configurations["compileClasspath"].filter { + // filter on the jar name. + it.name.startsWith("my-lib") + } + schemaFile.set(resources.text.fromArchive(archive, "schema.graphql").asFile()) +} +``` + + + + +```groovy +//build.gradle +graphqlGenerateClient { + packageName = "com.example.generated" + val archive = configurations["compileClasspath"].filter { + // filter on the jar name. + it.name.startsWith("my-lib") + } + schemaFile = resources.text.fromArchive(archive, "schema.graphql").asFile() +} +``` + + + + +## Generating Test Client + +GraphQL Kotlin test client code is generated based on the provided queries that will be executed against target GraphQL `schemaFile`. +Separate class is generated for each provided GraphQL query and are saved under specified `packageName`. + + + + + +```kotlin +// build.gradle.kts +import com.expediagroup.graphql.plugin.gradle.tasks.GraphQLGenerateTestClientTask + +val graphqlGenerateTestClient by tasks.getting(GraphQLGenerateTestClientTask::class) { + packageName.set("com.example.generated") + schemaFile.set(file("${project.projectDir}/mySchema.graphql")) +} +``` + + + + +```groovy +//build.gradle +graphqlGenerateTestClient { + packageName = "com.example.generated" + schemaFile = file("${project.projectDir}/mySchema.graphql") +} +``` + + + + +This will process all GraphQL queries located under `src/test/resources` and generate corresponding GraphQL Kotlin clients. +Generated classes will be automatically added to the project test compile sources. + +:::info +`graphqlGenerateTestClient` cannot be configured through the `graphql` extension and has to be explicitly configured. +::: + +## Minimal Client Configuration Example + +Following is the minimal configuration that runs introspection query against a target GraphQL server and generates a +corresponding schema. This generated schema is subsequently used to generate GraphQL client code based on the queries +provided under `src/main/resources` directory. + + + + + +```kotlin +// build.gradle.kts +import com.expediagroup.graphql.plugin.gradle.graphql + +graphql { + client { + endpoint = "http://localhost:8080/graphql" + packageName = "com.example.generated" + } +} +``` + +Above configuration is equivalent to the following + +```kotlin +// build.gradle.kts +import com.expediagroup.graphql.plugin.gradle.tasks.GraphQLGenerateClientTask +import com.expediagroup.graphql.plugin.gradle.tasks.GraphQLIntrospectSchemaTask + +val graphqlIntrospectSchema by tasks.getting(GraphQLIntrospectSchemaTask::class) { + endpoint.set("http://localhost:8080/graphql") +} +val graphqlGenerateClient by tasks.getting(GraphQLGenerateClientTask::class) { + packageName.set("com.example.generated") + schemaFile.set(graphqlIntrospectSchema.outputFile) + dependsOn("graphqlIntrospectSchema") +} +``` + + + + +```groovy +graphql { + client { + endpoint = "http://localhost:8080/graphql" + packageName = "com.example.generated" + } +} +``` + +Above configuration is equivalent to the following + +```groovy +// build.gradle +graphqlIntrospectSchema { + endpoint = "http://localhost:8080/graphql" +} +graphqlGenerateClient { + packageName = "com.example.generated" + schemaFile = graphqlIntrospectSchema.outputFile + dependsOn graphqlIntrospectSchema +} +``` + + + + +## Complete Client Configuration Example + +Following is a configuration example that downloads schema SDL from a target GraphQL server that is then used to generate +the GraphQL client data models using `kotlinx.serialization` that are based on the provided query. + + + + + +```kotlin +// build.gradle.kts +import com.expediagroup.graphql.plugin.gradle.config.GraphQLScalar +import com.expediagroup.graphql.plugin.gradle.config.GraphQLSerializer +import com.expediagroup.graphql.plugin.gradle.graphql + +plugins { + kotlin("plugin.serialization") version $kotlinVersion +} + +graphql { + client { + sdlEndpoint = "http://localhost:8080/sdl" + packageName = "com.example.generated" + // optional configuration + allowDeprecatedFields = true + customScalars = listOf(GraphQLScalar("UUID", "java.util.UUID", "com.example.UUIDScalarConverter")) + headers = mapOf("X-Custom-Header" to "My-Custom-Header") + queryFiles = listOf(file("${project.projectDir}/src/main/resources/queries/MyQuery.graphql")) + serializer = GraphQLSerializer.KOTLINX + timeout { + connect = 10_000 + read = 30_000 + } + } +} +``` + +Above configuration is equivalent to the following + +```kotlin +// build.gradle.kts +import com.expediagroup.graphql.plugin.gradle.config.GraphQLScalar +import com.expediagroup.graphql.plugin.gradle.config.GraphQLSerializer +import com.expediagroup.graphql.plugin.gradle.config.TimeoutConfiguration +import com.expediagroup.graphql.plugin.gradle.tasks.GraphQLDownloadSDLTask +import com.expediagroup.graphql.plugin.gradle.tasks.GraphQLGenerateClientTask + +plugins { + kotlin("plugin.serialization") version $kotlinVersion +} + +val graphqlDownloadSDL by tasks.getting(GraphQLDownloadSDLTask::class) { + endpoint.set("http://localhost:8080/sdl") + headers.put("X-Custom-Header", "My-Custom-Header") + timeoutConfig.set(TimeoutConfiguration(connect = 10_000, read = 30_000)) +} +val graphqlGenerateClient by tasks.getting(GraphQLGenerateClientTask::class) { + packageName.set("com.example.generated") + schemaFile.set(graphqlDownloadSDL.outputFile) + // optional + allowDeprecatedFields.set(true) + customScalars.add(GraphQLScalar("UUID", "java.util.UUID", "com.example.UUIDScalarConverter")) + queryFiles.from("${project.projectDir}/src/main/resources/queries/MyQuery.graphql") + serializer.set(GraphQLSerializer.KOTLINX) + + dependsOn("graphqlDownloadSDL") +} +``` + + + + +```groovy +// build.gradle +import com.expediagroup.graphql.plugin.gradle.config.GraphQLScalar +import com.expediagroup.graphql.plugin.gradle.config.GraphQLSerializer + +plugins { + id 'org.jetbrains.kotlin.plugin.serialization' version '$kotlinVersion' +} + +graphql { + client { + sdlEndpoint = "http://localhost:8080/sdl" + packageName = "com.example.generated" + // optional configuration + allowDeprecatedFields = true + customScalars = [new GraphQLScalar("UUID", "java.util.UUID", "com.example.UUIDScalarConverter")] + headers = ["X-Custom-Header" : "My-Custom-Header"] + queryFiles = [file("${project.projectDir}/src/main/resources/queries/MyQuery.graphql")] + serializer = GraphQLSerializer.KOTLINX + timeout { t -> + t.connect = 10000 + t.read = 30000 + } + } +} +``` + +Above configuration is equivalent to the following + +```groovy +//build.gradle +import com.expediagroup.graphql.plugin.gradle.config.GraphQLScalar +import com.expediagroup.graphql.plugin.gradle.config.GraphQLSerializer +import com.expediagroup.graphql.plugin.gradle.config.TimeoutConfiguration + +plugins { + id 'org.jetbrains.kotlin.plugin.serialization' version '$kotlinVersion' +} + +graphqlDownloadSDL { + endpoint = "http://localhost:8080/sdl" + headers["X-Custom-Header"] = "My-Custom-Header" + timeoutConfig = new TimeoutConfiguration(10000, 30000) +} +graphqlGenerateClient { + packageName = "com.example.generated" + schemaFile = graphqlDownloadSDL.outputFile + // optional + allowDeprecatedFields = true + customScalars.add(new GraphQLScalar("UUID", "java.util.UUID", "com.example.UUIDScalarConverter")) + queryFiles.from("${project.projectDir}/src/main/resources/queries/MyQuery.graphql") + serializer = GraphQLSerializer.KOTLINX + + dependsOn graphqlDownloadSDL +} +``` + + + + +## Generating Multiple Clients + +GraphQL Kotlin Gradle Plugin registers tasks for generation of a client queries targeting single GraphQL endpoint. You +can generate queries targeting additional endpoints by explicitly creating and configuring additional tasks. + + + + + +```kotlin +// build.gradle.kts +import com.expediagroup.graphql.plugin.gradle.tasks.GraphQLDownloadSDLTask +import com.expediagroup.graphql.plugin.gradle.tasks.GraphQLGenerateClientTask + +val graphqlDownloadSDL by tasks.getting(GraphQLDownloadSDLTask::class) { + endpoint.set("http://localhost:8080/sdl") +} +val graphqlGenerateClient by tasks.getting(GraphQLGenerateClientTask::class) { + packageName.set("com.example.generated.first") + schemaFile.set(graphqlDownloadSDL.outputFile) + queryFiles.from("${project.projectDir}/src/main/resources/queries/MyFirstQuery.graphql") + dependsOn("graphqlDownloadSDL") +} + +val graphqlDownloadOtherSDL by tasks.creating(GraphQLDownloadSDLTask::class) { + endpoint.set("http://localhost:8081/sdl") +} +val graphqlGenerateOtherClient by tasks.creating(GraphQLGenerateClientTask::class) { + packageName.set("com.example.generated.second") + schemaFile.set(graphqlDownloadOtherSDL.outputFile) + queryFiles.from("${project.projectDir}/src/main/resources/queries/MySecondQuery.graphql") + dependsOn("graphqlDownloadOtherSDL") +} +``` + + + + +```groovy +//build.gradle +import com.expediagroup.graphql.plugin.gradle.tasks.GraphQLDownloadSDLTask +import com.expediagroup.graphql.plugin.gradle.tasks.GraphQLGenerateClientTask + +graphqlDownloadSDL { + endpoint = "http://localhost:8080/sdl" +} +graphqlGenerateClient { + packageName = "com.example.generated.first" + schemaFile = graphqlDownloadSDL.outputFile + queryFiles.from("${project.projectDir}/src/main/resources/queries/MyFirstQuery.graphql") + + dependsOn graphqlDownloadSDL +} + +task graphqlDownloadOtherSDL(type: GraphQLDownloadSDLTask) { + endpoint = "http://localhost:8081/sdl" +} +task graphqlGenerateOtherClient(type: GraphQLGenerateClientTask) { + packageName = "com.other.generated.second" + schemaFile = graphqlDownloadOtherSDL.outputFile + queryFiles.from("${project.projectDir}/src/main/resources/queries/MySecondQuery.graphql") + + dependsOn graphqlDownloadOtherSDL +} +``` + + + diff --git a/website/versioned_docs/version-7.x.x/plugins/gradle-plugin-usage-graalvm.mdx b/website/versioned_docs/version-7.x.x/plugins/gradle-plugin-usage-graalvm.mdx new file mode 100644 index 0000000000..b5d835dd8f --- /dev/null +++ b/website/versioned_docs/version-7.x.x/plugins/gradle-plugin-usage-graalvm.mdx @@ -0,0 +1,270 @@ +--- +id: gradle-plugin-usage-graalvm +title: Gradle Plugin GraalVM Usage +sidebar_label: GraalVM Native Image +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +[GraalVm](https://www.graalvm.org/) is a high performance runtime from Oracle that supports Ahead-of-Time (AOT) compilation +that allows you to build native images. By shifting compilation to the build time, we can create binaries that are +**already optimized so they start almost instantaneously with immediate peak performance**. Compiled code is also much +more memory efficient as we no longer need the big memory overhead of running the JVM. + +In order to generate GraalVM Native image we need to provide the information about all the dynamic JVM features that our +application relies on. Since `graphql-kotlin` generates schema directly from your source code using reflections, we need +to capture this information to make it available at build time. By default, `graphql-kotlin` also relies on classpath scanning +to look up all polymorphic types implementations as well as to locate all the (Apollo) Federated entity types. + +## Ktor GraalVM Native Image + +Given following schema + +```kotlin +class NativeExampleQuery : Query { + fun helloWorld() = "Hello World" +} +``` + +We first need to configure our server to avoid class scanning. Even though our example schema does not contain any +polymorphic types, **we still need to explicitly opt-out of class scanning by providing type hierarchy**. + +```kotlin +fun Application.graphQLModule() { + install(GraphQL) { + schema { + packages = listOf("com.example") + queries = listOf( + HelloWorldQuery() + ) + // mapping between interfaces/union KClass and their implementation KClasses + typeHierarchy = mapOf() + } + } + install(Routing) { + graphQLPostRoute() + graphiQLRoute() + } +} +``` + +We then need to update our build with native configuration + + + + + +```kotlin +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("jvm") version "1.7.21" + application +} + +dependencies { + implementation("com.expediagroup", "graphql-kotlin-ktor-server", $latestGraphQLKotlinVersion) + implementation("ch.qos.logback", "logback-classic", "1.4.7") + implementation("io.ktor", "ktor-client-cio", "2.2.4") +} + +tasks.withType { + kotlinOptions.jvmTarget = "17" +} + +application { + mainClass.set("com.example.ApplicationKt") +} +``` + + + + +```kotlin +import com.expediagroup.graphql.plugin.gradle.graphql +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("jvm") version "1.7.21" + application + id("org.graalvm.buildtools.native") version "0.9.21" // (1) + id("com.expediagroup.graphql") version $latestGraphQLKotlinVersion // (2) +} + +dependencies { + implementation("com.expediagroup", "graphql-kotlin-ktor-server", $latestGraphQLKotlinVersion) + implementation("ch.qos.logback", "logback-classic", "1.4.7") + implementation("io.ktor", "ktor-client-cio", "2.2.4") +} + +tasks.withType { + kotlinOptions.jvmTarget = "17" +} + +application { + mainClass.set("com.example.ApplicationKt") +} + +graalvmNative { // (3) + toolchainDetection.set(false) + binaries { + named("main") { + verbose.set(true) + buildArgs.add("--initialize-at-build-time=io.ktor,kotlin,ch.qos.logback,org.slf4j") + buildArgs.add("-H:+ReportExceptionStackTraces") + } + // enable using reachability metadata repository + metadataRepository { + enabled.set(true) + } + } +} + +graphql { // (4) + graalVm { + packages = listOf("com.example") + } +} +``` + +We need to make couple changes to our build file to be able to generate GraalVM native image: + +1. Apply [GraalVM Native Gradle plugin](https://graalvm.github.io/native-build-tools/latest/gradle-plugin.html) +2. Apply GraphQL Kotlin Gradle plugin +3. Configure GraalVM native image +4. Configure GraphQL Kotlin GraalVM extension + + + + +Once the build is configured we can then generate our native image by running `nativeCompile` task. + +```shell +> ./gradlew nativeCompile +``` + +Native executable image will then be generated under `build/native/nativeCompile` directory. + +## Spring GraalVM Native Image + +Given following schema + +```kotlin +@Component +class NativeExampleQuery : Query { + fun helloWorld() = "Hello World" +} +``` + +We first need to configure our server to avoid class scanning. Even though our example schema does not contain any +polymorphic types, **we still need to explicitly opt-out of class scanning by providing type hierarchy**. + +```kotlin +@SpringBootApplication +class Application { + @Bean + fun typeResolver(): GraphQLTypeResolver = SimpleTypeResolver(mapOf()) +} + +fun main(args: Array) { + runApplication(*args) +} +``` + +We then need to update our build with native configuration + + + + + +```kotlin +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("jvm") version "1.7.21" + kotlin("plugin.spring") version "1.7.21" + id("org.springframework.boot") version "3.0.5" +} + +dependencies { + implementation("com.expediagroup", "graphql-kotlin-spring-server", $latestGraphQLKotlinVersion) +} + +tasks.withType { + kotlinOptions.jvmTarget = "17" +} +``` + + + + +```kotlin +import com.expediagroup.graphql.plugin.gradle.graphql +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("jvm") version "1.7.21" + kotlin("plugin.spring") version "1.7.21" + id("org.springframework.boot") version "3.0.6" + id("org.graalvm.buildtools.native") version "0.9.21" // (1) + id("com.expediagroup.graphql") version $latestGraphQLKotlinVersion // (2) +} + +dependencies { + implementation("com.expediagroup", "graphql-kotlin-spring-server", $latestGraphQLKotlinVersion) +} + +tasks.withType { + kotlinOptions.jvmTarget = "17" +} + +graalvmNative { // (3) + toolchainDetection.set(false) + binaries { + named("main") { + verbose.set(true) + } + // enable using reachability metadata repository + metadataRepository { + enabled.set(true) + } + } +} + +graphql { // (4) + graalVm { + packages = listOf("com.example") + } +} +``` + +We need to make couple changes to our build file to be able to generate GraalVM native image: + +1. Apply [GraalVM Native Gradle plugin](https://graalvm.github.io/native-build-tools/latest/gradle-plugin.html) +2. Apply GraphQL Kotlin Gradle plugin +3. Configure GraalVM native image +4. Configure GraphQL Kotlin GraalVM extension + + + + +Once the build is configured we can then generate our native image by running `nativeCompile` task. + +```shell +> ./gradlew nativeCompile +``` + +Native executable image will then be generated under `build/native/nativeCompile` directory. diff --git a/website/versioned_docs/version-7.x.x/plugins/gradle-plugin-usage-sdl.mdx b/website/versioned_docs/version-7.x.x/plugins/gradle-plugin-usage-sdl.mdx new file mode 100644 index 0000000000..55b99ca166 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/plugins/gradle-plugin-usage-sdl.mdx @@ -0,0 +1,171 @@ +--- +id: gradle-plugin-usage-sdl +title: Gradle Plugin SDL Usage +sidebar_label: Generating SDL +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +GraphQL Kotlin follows a code-first approach where schema is auto generated from your source code at runtime. GraphQL Kotlin +plugins can be used to generate schema as a build time artifact. This allows you to seamlessly integrate with various +GraphQL tools that may require a schema artifact as an input (e.g. to perform backwards compatibility checks, etc). + +## Generating SDL + +GraphQL schema can be generated directly from your source code using reflections. `graphqlGenerateSDL` will scan your +classpath looking for classes implementing `Query`, `Mutation` and `Subscription` marker interfaces and then generates the +corresponding GraphQL schema using `graphql-kotlin-schema-generator` and default `NoopSchemaGeneratorHooks`. In order to +limit the amount of packages to scan, this task requires users to provide a list of `packages` that can contain GraphQL +types. + + + + + +```kotlin +// build.gradle.kts +import com.expediagroup.graphql.plugin.gradle.graphql + +graphql { + schema { + packages = listOf("com.example") + } +} +``` + +Above configuration is equivalent to the following task definition + +```kotlin +// build.gradle.kts +import com.expediagroup.graphql.plugin.gradle.tasks.GraphQLGenerateSDLTask + +val graphqlGenerateSDL by tasks.getting(GraphQLGenerateSDLTask::class) { + packages.set(listOf("com.example")) +} +``` + + + + +```groovy +// build.gradle +graphql { + schema { + packages = ["com.example"] + } +} +``` + +Above configuration is equivalent to the following task definition + +```groovy +//build.gradle +graphqlGenerateSDL { + packages = ["com.example"] +} +``` + + + + +:::info +This task does not automatically configure itself to be part of your build lifecycle. You will need to explicitly +invoke it OR configure it as a dependency of some other task. +::: + +## Using Custom Hooks Provider + +Plugin will default to use `NoopSchemaGeneratorHooks` to generate target GraphQL schema. If your project uses custom hooks +or needs to generate the federated GraphQL schema, you will need to provide an instance of `SchemaGeneratorHooksProvider` +service provider that will be used to create an instance of your custom hooks. + +`graphqlGenerateSDL` utilizes [ServiceLoader](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ServiceLoader.html) +mechanism to dynamically load available `SchemaGeneratorHooksProvider` service providers from the classpath. Service provider +can be provided as part of your project, included in one of your project dependencies or through explicitly provided artifact. +See [Schema Generator Hooks Provider](./hooks-provider.mdx) for additional details on how to create custom hooks service provider. +Configuration below shows how to configure GraphQL Kotlin plugin with explicitly provided artifact to generate federated +GraphQL schema. + + + + + +```kotlin +// build.gradle.kts +import com.expediagroup.graphql.plugin.gradle.graphql + +graphql { + schema { + packages = listOf("com.example") + } +} + +dependencies { + graphqlSDL("com.expediagroup:graphql-kotlin-federated-hooks-provider:$graphQLKotlinVersion") +} +``` + +Above configuration is equivalent to the following task definition + +```kotlin +// build.gradle.kts +import com.expediagroup.graphql.plugin.gradle.tasks.GraphQLGenerateSDLTask + +val graphqlGenerateSDL by tasks.getting(GraphQLGenerateSDLTask::class) { + packages.set(listOf("com.example")) +} + +dependencies { + graphqlSDL("com.expediagroup:graphql-kotlin-federated-hooks-provider:$graphQLKotlinVersion") +} +``` + + + + +```groovy +// build.gradle +graphql { + schema { + packages = ["com.example"] + } +} + +dependencies { + graphqlSDL "com.expediagroup:graphql-kotlin-federated-hooks-provider:$DEFAULT_PLUGIN_VERSION" +} +``` + +Above configuration is equivalent to the following task definition + +```groovy +//build.gradle +graphqlGenerateSDL { + packages = ["com.example"] +} + +dependencies { + graphqlSDL "com.expediagroup:graphql-kotlin-federated-hooks-provider:$DEFAULT_PLUGIN_VERSION" +} +``` + + + + +:::info +This task does not automatically configure itself to be part of your build lifecycle. You will need to explicitly +invoke it OR configure it as a dependency of some other task. +::: diff --git a/website/versioned_docs/version-7.x.x/plugins/hooks-provider.mdx b/website/versioned_docs/version-7.x.x/plugins/hooks-provider.mdx new file mode 100644 index 0000000000..3d7b90cc7d --- /dev/null +++ b/website/versioned_docs/version-7.x.x/plugins/hooks-provider.mdx @@ -0,0 +1,138 @@ +--- +id: hooks-provider +title: Schema Generator Hooks Provider +--- + + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +GraphQL Kotlin plugins can generate GraphQL schema as your build artifact directly from your source code. Plugins will scan +your classpath for classes implementing `graphql-kotlin-server` marker `Query`, `Mutation` and `Subscription` interfaces +and then generate corresponding GraphQL schema using `graphql-kotlin-schema-generator`. By default, plugins will generate +the schema using `NoopSchemaGeneratorHooks`. If your project uses custom hooks or needs to generate the federated GraphQL +schema, you will need to provide an instance of `SchemaGeneratorHooksProvider` that will be used to create an instance of +your custom hooks. + +`SchemaGeneratorHooksProvider` is a service provider interface that exposes a single `hooks` method to generate an instance +of `SchemaGeneratorHooks` that will be used to generate your schema. By utilizing Java [ServiceLoader](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ServiceLoader.html) +we can dynamically load your custom provider from the classpath. Service provider can be provided as part of your project +sources, included inside of one of your project dependencies or through explicitly provided artifact. Since we need to be +able to deterministically choose a single hooks provider, generation of schema will fail if there are multiple providers +on the classpath. + +## Federated Hooks Provider + +If no custom hook providers are specified, `graphql-kotlin` plugins will default to use `NoopSchemaGeneratorHooks`. If you +want to generate Federated schemas, you need to explicitly specify a dependency on `graphql-kotlin-federated-hooks-provider`. + + + + + +```kotlin +// build.gradle.kts +graphqlSDL("com.expediagroup", "graphql-kotlin-federated-hooks-provider", latestVersion) +``` + + + + +```xml + + com.expediagroup + graphql-kotlin-federated-hooks-provider + ${latestVersion} + +``` + + + + +## Creating Custom Hooks Service Provider + +### Add dependency on graphql-kotlin-hooks-provider + +`SchemaGeneratorHooksProvider` interface is defined in `graphql-kotlin-hooks-provider` module. + + + + + +```kotlin +// build.gradle.kts +implementation("com.expediagroup", "graphql-kotlin-hooks-provider", latestVersion) +``` + + + + +```xml + + com.expediagroup + graphql-kotlin-hooks-provider + ${latestVersion} + +``` + + + + +### Create new SchemaGeneratorHooksProvider implementation + +Service provider implementation has to implement `SchemaGeneratorHooksProvider` interface that provides a way to instantiate +schema generator hooks that will be used to generate the GraphQL schema. + +```kotlin +package com.example + +class MyCustomSchemaGeneratorHooksProvider : SchemaGeneratorHooksProvider { + override fun hooks(): SchemaGeneratorHooks = MyCustomHooks() +} +``` + +### Create provider configuration file + +Service loader provider configuration file should be created under JAR `/META-INF/services` directory (e.g. `src/main/resources/META-INF/services` +in default project structure). Name of the provider configuration should be fully qualified service provider interface name, i.e. +`com.expediagroup.graphql.plugin.schema.hooks.SchemaGeneratorHooksProvider` and contain single entry - a fully qualified +name of the service provider implementation. + +Using the example service provider implementation from the above, our project structure should look like + +``` +my-project +|- src + |- main + |- kotlin + |- com + |- example + |- MyCustomSchemaGeneratorHooksProvider.kt + |- resources + |- META-INF + |- services + |- com.expediagroup.graphql.plugin.schema.hooks.SchemaGeneratorHooksProvider + +``` +Our service provider configuration file should have following content + +```text +com.example.MyCustomSchemaGeneratorHooksProvider +``` + +## Limitations + +We don't support Java 9 module mechanism for declaring `ServiceLoader` implementations. As a workaround, you have to define +your service providers in the provider configuration file under `META-INF/services`. diff --git a/website/versioned_docs/version-7.x.x/plugins/maven-plugin-goals.md b/website/versioned_docs/version-7.x.x/plugins/maven-plugin-goals.md new file mode 100644 index 0000000000..92f5e8c1c1 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/plugins/maven-plugin-goals.md @@ -0,0 +1,259 @@ +--- +id: maven-plugin-goals +title: Maven Plugin Goals +sidebar_label: Goals Overview +--- + +GraphQL Kotlin Maven Plugin provides functionality to generate a lightweight GraphQL HTTP client and generate GraphQL +schema directly from your source code. + +:::info +This plugin is dependent on Kotlin compiler plugin as it generates Kotlin source code that needs to be compiled. +::: + +## Goals + +You can find detailed information about `graphql-kotlin-maven-plugin` and all its goals by running `mvn help:describe -Dplugin=com.expediagroup:graphql-kotlin-maven-plugin -Ddetail`. + +### download-sdl + +GraphQL endpoints are often public and as such many servers might disable introspection queries in production environment. +Since GraphQL schema is needed to generate type safe clients, as alternative GraphQL servers might expose private +endpoints (e.g. accessible only from within network, etc) that could be used to download schema in Schema Definition +Language (SDL) directly. This Mojo attempts to download schema from the specified `graphql.endpoint`, validates the +result whether it is a valid schema and saves it locally in a specified target file (defaults to `schema.graphql` under +build directory). In general, this goal provides limited functionality by itself and instead should be used to generate +input for the subsequent `generate-client` goal. + +**Attributes** + +* *Default Lifecycle Phase*: `generate-sources` + +**Parameters** + +| Property | Type | Required | Description | +| -------- | ---- | -------- | ----------- | +| `endpoint` | String | yes | Target GraphQL server SDL endpoint that will be used to download schema.
**User property is**: `graphql.endpoint`. | +| `headers` | `Map` | | Optional HTTP headers to be specified on a SDL request. +| `timeoutConfiguration` | TimeoutConfiguration | | Optional timeout configuration (in milliseconds) to download schema from SDL endpoint before we cancel the request.
**Default values are:**
connect timeout = 5000
read timeout = 15000.
| +| `schemaFile` | File | | Target schema file.
**Default value is**: `${project.build.directory}/schema.graphql`
**User property is**: `graphql.schemaFile`. | + +**Parameter Details** + +* *timeoutConfiguration* - Timeout configuration that allows you to specify connect and read timeout values in milliseconds. + +```xml + + + 1000 + 30000 + +``` + +### generate-client + +Generate GraphQL client code based on the provided GraphQL schema and target queries. + +**Attributes** + +* *Default Lifecycle Phase*: `generate-sources` +* *Requires Maven Project* +* Generated classes are automatically added to the list of compiled sources. + +**Parameters** + +| Property | Type | Required | Description | +|---------------------------|----------------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `allowDeprecatedFields` | Boolean | | Boolean flag indicating whether selection of deprecated fields is allowed or not.
**Default value is:** `false`.
**User property is**: `graphql.allowDeprecatedFields`. | +| `customScalars` | `List` | | List of custom GraphQL scalar to converter mappings containing information about corresponding Java type and converter that should be used to serialize/deserialize values. | +| `outputDirectory` | File | | Target directory where to store generated files.
**Default value is**: `${project.build.directory}/generated-sources/graphql` | +| `packageName` | String | yes | Target package name for generated code.
**User property is**: `graphql.packageName`. | +| `parserOptions` | GraphQLParserOptions | | Configures the settings used when parsing GraphQL queries and schema definition language documents. | +| `queryFileDirectory` | File | | Directory file containing GraphQL queries. Instead of specifying a directory you can also specify list of query file by using `queryFiles` property instead.
**Default value is:** `src/main/resources`. | +| `queryFiles` | `List` | | List of query files to be processed. Instead of a list of files to be processed you can also specify `queryFileDirectory` directory containing all the files. If this property is specified it will take precedence over the corresponding directory property. | +| `schemaFile` | String | | GraphQL schema file that will be used to generate client code.
**Default value is**: `${project.build.directory}/schema.graphql`
**User property is**: `graphql.schemaFile`. | +| `serializer` | GraphQLSerializer | | JSON serializer that will be used to generate the data classes.
**Default value is:** `GraphQLSerializer.JACKSON`. | +| `useOptionalInputWrapper` | Boolean | | Boolean opt-in flag to wrap nullable arguments in `OptionalInput` that distinguish between `null` and undefined/omitted value.
**Default value is:** `false`.
**User property is**: `graphql.useOptionalInputWrapper` | + +**Parameter Details** + + * *customScalars* - List of custom GraphQL scalars. Objects contain target GraphQL scalar name, corresponding Java type + and converter that should be used to serialize/deserialize values. + + ```xml + + + + UUID + + java.util.UUID + + com.example.UUIDScalarConverter + + + ``` + * *parserOptions* - Configure options for parsing GraphQL queries and schema definition language documents. Settings here override the defaults set by GraphQL Java. + + ```xml + + + 15000 + + 200000 + + 1048576 + + 500 + + false + + true + + true + + ``` + +### generate-graalvm-metadata + +Generates [GraalVM Reachability Metadata](https://www.graalvm.org/latest/reference-manual/native-image/metadata/) for +`graphql-kotlin` servers. Based on the GraphQL schema it will generate `native-image.properties`, `reflect-config.json` +and `resource-config.json` metadata files under `target/classes/META-INF/native-image///graphql` + +This task should be used in tandem with [GraalVM Native Plugin](https://graalvm.github.io/native-build-tools/latest/maven-plugin.html) +to simplify generation of GraalVM native `graphql-kotlin` servers. + +**Attributes** + +* *Default Lifecycle Phase*: `process-classes` +* *Requires Maven Project* + +**Parameters** + +| Property | Type | Required | Description | +| -------- |------| -------- |-------------| +| `packages` | `List` | yes | List of supported packages that can be can contain GraphQL schema. | +| `mainClassName` | String | | Application main class name. | + +### generate-sdl + +Generates GraphQL schema in SDL format from your source code using reflections. Utilizes `graphql-kotlin-schema-generator` +to generate the schema from classes implementing `graphql-kotlin-server` marker `Query`, `Mutation` and `Subscription` interfaces. +In order to limit the amount of packages to scan, this mojo requires users to provide a list of `packages` that can contain +GraphQL types. + +This MOJO utilizes [ServiceLoader](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ServiceLoader.html) +mechanism to dynamically load available `SchemaGeneratorHooksProvider` service providers from the classpath. Service provider +can be provided as part of your project, included in one of your project dependencies or through explicitly provided artifact. +See [Schema Generator Hooks Provider](./hooks-provider.mdx) for additional details on how to create custom hooks service +provider. Configuration below shows how to configure GraphQL Kotlin plugin with explicitly provided artifact. + +**Attributes** + +* *Default Lifecycle Phase*: `process-classes` +* *Requires Maven Project* + +**Parameters** + +| Property | Type | Required | Description | +| -------- | ---- | -------- | ----------- | +| `packages` | `List` | yes | List of supported packages that can be scanned to generate SDL. | +| `schemaFile` | File | | Target GraphQL schema file to be generated.
**Default value is:** `${project.buildDir}/schema.graphql` | + +### generate-test-client + +Generate GraphQL test client code based on the provided GraphQL schema and target queries. + +**Attributes** + +* *Default Lifecycle Phase*: `generate-test-sources` +* *Requires Maven Project* +* Generated classes are automatically added to the list of test compiled sources. + +**Parameters** + +| Property | Type | Required | Description | +| -------- | ---- | -------- | ----------- | +| `allowDeprecatedFields` | Boolean | | Boolean flag indicating whether selection of deprecated fields is allowed or not.
**Default value is:** `false`.
**User property is**: `graphql.allowDeprecatedFields`. | +| `customScalars` | `List` | | List of custom GraphQL scalar to converter mappings containing information about corresponding Java type and converter that should be used to serialize/deserialize values. | +| `outputDirectory` | File | | Target directory where to store generated files.
**Default value is**: `${project.build.directory}/generated-test-sources/graphql` | +| `packageName` | String | yes | Target package name for generated code.
**User property is**: `graphql.packageName`. | +| `queryFileDirectory` | File | | Directory file containing GraphQL queries. Instead of specifying a directory you can also specify list of query file by using `queryFiles` property instead.
**Default value is:** `src/test/resources`. | +| `queryFiles` | `List` | | List of query files to be processed. Instead of a list of files to be processed you can also specify `queryFileDirectory` directory containing all the files. If this property is specified it will take precedence over the corresponding directory property. | +| `serializer` | GraphQLSerializer | | JSON serializer that will be used to generate the data classes.
**Default value is:** `GraphQLSerializer.JACKSON`. | +| `schemaFile` | String | | GraphQL schema file that will be used to generate client code.
**Default value is**: `${project.build.directory}/schema.graphql`
**User property is**: `graphql.schemaFile`. | +| `useOptionalInputWrapper` | Boolean | | Boolean opt-in flag to wrap nullable arguments in `OptionalInput` that distinguish between `null` and undefined/omitted value.
**Default value is:** `false`.
**User property is**: `graphql.useOptionalInputWrapper` | + +**Parameter Details** + + * *customScalars* - List of custom GraphQL scalars. Objects contain target GraphQL scalar name, corresponding Java type + and converter that should be used to serialize/deserialize values. + +```xml + + + + + UUID + + java.util.UUID + + com.example.UUIDScalarConverter + + + +``` + +* *parserOptions* - Configure options for parsing GraphQL queries and schema definition language documents. Settings here override the defaults set by GraphQL Java. + + ```xml + + + 15000 + + 200000 + + 1048576 + + 500 + + false + + true + + true + + ``` + +### introspect-schema + +Executes GraphQL introspection query against specified `graphql.endpoint` and saves the result locally to a target file +(defaults to `schema.graphql` under build directory). In general, this goal provides limited functionality by itself and +instead should be used to generate input for the subsequent `generate-client` goal. + +**Attributes** + +* *Default Lifecycle Phase*: `generate-sources` + +**Parameters** + +| Property | Type | Required | Description | +| -------- | ---- | -------- | ----------- | +| `endpoint` | String | yes | Target GraphQL server endpoint that will be used to execute introspection queries.
**User property is**: `graphql.endpoint`. | +| `headers` | `Map` | | Optional HTTP headers to be specified on an introspection query. | +| `timeoutConfiguration` | TimeoutConfiguration | | Optional timeout configuration (in milliseconds) to download schema from SDL endpoint before we cancel the request.
**Default values are:**
connect timeout = 5000
read timeout = 15000.
| +| `schemaFile` | File | | Target schema file.
**Default value is**: `${project.build.directory}/schema.graphql`
**User property is**: `graphql.schemaFile`. | +| `streamResponse` | Boolean | | Boolean property to indicate whether to use streamed (chunked) responses.
Default value is**: true. | + +**Parameter Details** + +* *timeoutConfiguration* - Timeout configuration that allows you to specify connect and read timeout values in milliseconds. + +```xml + + + 1000 + 30000 + +``` diff --git a/website/versioned_docs/version-7.x.x/plugins/maven-plugin-usage-client.md b/website/versioned_docs/version-7.x.x/plugins/maven-plugin-usage-client.md new file mode 100644 index 0000000000..d91a209ba1 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/plugins/maven-plugin-usage-client.md @@ -0,0 +1,456 @@ +--- +id: maven-plugin-usage-client +title: Maven Plugin Client Usage +sidebar_label: Generating Client +--- + +GraphQL Kotlin plugins can be used to generate a lightweight type-safe GraphQL HTTP clients. See examples below for more +information about the client generating tasks. + +## Downloading Schema SDL + +Download SDL Mojo requires target GraphQL server `endpoint` to be specified. Task can be executed directly from the +command line by explicitly specifying `graphql.endpoint` property. + +```shell script +$ mvn com.expediagroup:graphql-kotlin-maven-plugin:download-sdl -Dgraphql.endpoint="http://localhost:8080/sdl" +``` + +Mojo can also be configured in your Maven build file + +```xml + + com.expediagroup + graphql-kotlin-maven-plugin + ${graphql-kotlin.version} + + + + download-sdl + + + http://localhost:8080/sdl + + + + +``` + +By default, `download-sdl` goal will be executed as part of the `generate-sources` [build lifecycle phase](https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html). + +## Introspecting Schema + +Introspection Mojo requires target GraphQL server `endpoint` to be specified. Task can be executed directly from the +command line by explicitly specifying `graphql.endpoint` property + +```shell script +$ mvn com.expediagroup:graphql-kotlin-maven-plugin:introspect-schema -Dgraphql.endpoint="http://localhost:8080/graphql" +``` + +Mojo can also be configured in your Maven build file + +```xml + + com.expediagroup + graphql-kotlin-maven-plugin + ${graphql-kotlin.version} + + + + introspect-schema + + + http://localhost:8080/graphql + + + + +``` + +By default, `introspect-schema` goal will be executed as part of the `generate-sources` [build lifecycle phase](https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html). + +## Generating Client + +This Mojo generates GraphQL client code based on the provided queries using target GraphQL `schemaFile`. Classes are +generated under specified `packageName`. When using default configuration and storing GraphQL queries under `src/main/resources` +directories, task can be executed directly from the command line by explicitly providing required properties. + +```shell script +$ mvn com.expediagroup:graphql-kotlin-maven-plugin:generate-client -Dgraphql.schemaFile="mySchema.graphql" -Dgraphql.packageName="com.example.generated" +``` + +Mojo can also be configured in your Maven build file to become part of your build lifecycle. Plugin also provides additional +configuration options that are not available on command line. + +```xml + + com.expediagroup + graphql-kotlin-maven-plugin + ${graphql-kotlin.version} + + + + generate-client + + + com.example.generated + mySchema.graphql + + + + +``` + +This will process all GraphQL queries located under `src/main/resources` and generate corresponding GraphQL Kotlin client +data models. Generated classes will be automatically added to the project compile sources. + +:::note +You might need to explicitly add generated clients to your project sources for your IDE to recognize them. See +[build-helper-maven-plugin](https://www.mojohaus.org/build-helper-maven-plugin/) for details. +::: + +## Generating Client with Custom Scalars + +By default, all custom GraphQL scalars will be serialized as Strings. You can override this default behavior by specifying +custom [scalar converter](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/graphql-kotlin-client/src/main/kotlin/com/expediagroup/graphql/client/converter/ScalarConverter.kt). + +For example given following custom scalar in our GraphQL schema + +```graphql +scalar UUID +``` + +We can create a custom converter to automatically convert this custom scalar to `java.util.UUID` + +```kotlin +package com.example + +import com.expediagroup.graphql.client.converter.ScalarConverter +import java.util.UUID + +class UUIDScalarConverter : ScalarConverter { + override fun toScalar(rawValue: Any): UUID = UUID.fromString(rawValue.toString()) + override fun toJson(value: UUID): String = value.toString() +} +``` + +Afterwards we need to configure our plugin to use this custom converter + +```xml + + com.expediagroup + graphql-kotlin-maven-plugin + ${graphql-kotlin.version} + + + + generate-client + + + false + + + + UUID + + java.util.UUID + + com.example.UUIDScalarConverter + + + com.example.generated + mySchema.graphql + + + + +``` + +## Generating Client using Kotlinx Serialization + +GraphQL Kotlin plugins default to generate client data models that are compatible with [Jackson](https://github.com/FasterXML/jackson). +We can change this default behavior by explicitly specifying serializer type and configuring `kotlinx.serialization` compiler +plugin. See [kotlinx.serialization documentation](https://github.com/Kotlin/kotlinx.serialization) for details. + +```xml + + + + + org.jetbrains.kotlinx + kotlinx-serialization-json + ${kotlinx-serialization.version} + + + + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + 1.8 + + kotlinx-serialization + + + + + compile + + compile + + + + test-compile + + test-compile + + + + + + org.jetbrains.kotlin + kotlin-maven-serialization + ${kotlin.version} + + + + + com.expediagroup + graphql-kotlin-maven-plugin + ${graphql-kotlin.version} + + + + generate-client + + + com.example.generated + mySchema.graphql + + KOTLINX + + + + + + + +``` + +## Generating Test Client + +This Mojo generates GraphQL Kotlin test client code based on the provided queries using target GraphQL `schemaFile`. Classes +are generated under specified `packageName`. When using default configuration and storing GraphQL queries under `src/test/resources` +directories, task can be executed directly from the command line by explicitly providing required properties. + +```shell script +$ mvn com.expediagroup:graphql-kotlin-maven-plugin:generate-test-client -Dgraphql.schemaFile="mySchema.graphql" -Dgraphql.packageName="com.example.generated" +``` + +Mojo can also be configured in your Maven build file to become part of your build lifecycle. Plugin also provides additional +configuration options that are not available on command line. + +```xml + + com.expediagroup + graphql-kotlin-maven-plugin + ${graphql-kotlin.version} + + + + generate-test-client + + + com.example.generated + mySchema.graphql + + + + +``` + +This will process all GraphQL queries located under `src/test/resources` and generate corresponding GraphQL Kotlin test clients. +Generated classes will be automatically added to the project test compile sources. + +:::note +You might need to explicitly add generated test clients to your project test sources for your IDE to recognize them. +See [build-helper-maven-plugin](https://www.mojohaus.org/build-helper-maven-plugin/) for details. +::: + +## Minimal Configuration Example + +Following is the minimal configuration that runs introspection query against a target GraphQL server and generates a corresponding schema. +This generated schema is subsequently used to generate GraphQL client code based on the queries provided under `src/main/resources` directory. + +```xml + + com.expediagroup + graphql-kotlin-maven-plugin + ${graphql-kotlin.version} + + + + introspect-schema + generate-client + + + http://localhost:8080/graphql + com.example.generated + + + + +``` + +:::info +Both `introspect-schema` and `generate-client` goals are bound to the same `generate-sources` Maven lifecycle phase. +As opposed to Gradle, Maven does not support explicit ordering of different goals bound to the same build phase. Maven +Mojos will be executed in the order they are defined in your `pom.xml` build file. +::: + +## Complete Configuration Example + +Following is a configuration example that downloads schema SDL from a target GraphQL server that is then used to generate +the GraphQL client data models using `kotlinx.serialization` that are based on the provided query. + +```xml + + + + + org.jetbrains.kotlinx + kotlinx-serialization-json + ${kotlinx-serialization.version} + + + + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + 1.8 + + kotlinx-serialization + + + + + compile + + compile + + + + test-compile + + test-compile + + + + + + org.jetbrains.kotlin + kotlin-maven-serialization + ${kotlin.version} + + + + + com.expediagroup + graphql-kotlin-maven-plugin + ${graphql-kotlin.version} + + + + download-sdl + generate-client + + + http://localhost:8080/sdl + com.example.generated + + ${project.build.directory}/mySchema.graphql + true + + + + UUID + + java.util.UUID + + com.example.UUIDScalarConverter + + + + My-Custom-Header + + + + 1000 + 30000 + + + ${project.basedir}/src/main/resources/queries/MyQuery.graphql + + KOTLINX + + + + + + + +``` + +## Generating Multiple Clients + +In order to generate GraphQL clients targeting multiple endpoints, we need to configure separate executions targeting +different endpoints. + +```xml + + com.expediagroup + graphql-kotlin-maven-plugin + ${graphql-kotlin.version} + + + generate-first-client + + introspect-schema + generate-client + + + http://localhost:8080/graphql + com.example.generated.first + + ${project.basedir}/src/main/resources/queries/FirstQuery.graphql + + + + + generate-second-client + + introspect-schema + generate-client + + + http://localhost:8081/graphql + com.example.generated.second + + ${project.basedir}/src/main/resources/queries/SecondQuery.graphql + + + + + +``` diff --git a/website/versioned_docs/version-7.x.x/plugins/maven-plugin-usage-graalvm.md b/website/versioned_docs/version-7.x.x/plugins/maven-plugin-usage-graalvm.md new file mode 100644 index 0000000000..fce220184a --- /dev/null +++ b/website/versioned_docs/version-7.x.x/plugins/maven-plugin-usage-graalvm.md @@ -0,0 +1,538 @@ +--- +id: maven-plugin-usage-graalvm +title: Maven Plugin GraalVM Usage +sidebar_label: GraalVM Native Image +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +[GraalVm](https://www.graalvm.org/) is a high performance runtime from Oracle that supports Ahead-of-Time (AOT) compilation +that allows you to build native images. By shifting compilation to the build time, we can create binaries that are +**already optimized so they start almost instantaneously with immediate peak performance**. Compiled code is also much +more memory efficient as we no longer need the big memory overhead of running the JVM. + +In order to generate GraalVM Native image we need to provide the information about all the dynamic JVM features that our +application relies on. Since `graphql-kotlin` generates schema directly from your source code using reflections, we need +to capture this information to make it available at build time. By default, `graphql-kotlin` also relies on classpath scanning +to look up all polymorphic types implementations as well as to locate all the (Apollo) Federated entity types. + +## Ktor GraalVM Native Image + +Given following schema + +```kotlin +class NativeExampleQuery : Query { + fun helloWorld() = "Hello World" +} +``` + +We first need to configure our server to avoid class scanning. Even though our example schema does not contain any +polymorphic types, **we still need to explicitly opt-out of class scanning by providing type hierarchy**. + +```kotlin +fun Application.graphQLModule() { + install(GraphQL) { + schema { + packages = listOf("com.example") + queries = listOf( + HelloWorldQuery() + ) + // mapping between interfaces/union KClass and their implementation KClasses + typeHierarchy = mapOf() + } + } + install(Routing) { + graphQLPostRoute() + graphiQLRoute() + } +} +``` + +We then need to update our build with native configuration + + + + + +```xml + + + 4.0.0 + + com.example + example-graalvm-server + 1.0-SNAPSHOT + + + 17 + 1.7.22 + ${latestGraphqlKotlinVersion} + + 2.2.4 + 1.4.7 + + + + + com.expediagroup + graphql-kotlin-ktor-server + ${graphql-kotlin.version} + + + io.ktor + ktor-server-cio-jvm + ${ktor.version} + + + ch.qos.logback + logback-classic + ${logback.version} + + + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/test/kotlin + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + ${kotlin.jvmTarget} + + + + compile + + compile + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.3.0 + + + + true + com.example.ApplicationKt + + + + + + + +``` + + + + +```xml + + + 4.0.0 + + com.example + example-graalvm-server + 1.0-SNAPSHOT + + + 17 + 1.7.22 + ${latestGraphqlKotlinVersion} + + 2.2.4 + 1.4.7 + 0.9.21 + + + + + com.expediagroup + graphql-kotlin-ktor-server + ${graphql-kotlin.version} + + + io.ktor + ktor-server-cio-jvm + ${ktor.version} + + + ch.qos.logback + logback-classic + ${logback.version} + + + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/test/kotlin + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + ${kotlin.jvmTarget} + + + + compile + + compile + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.3.0 + + + + true + com.example.ApplicationKt + + + + + + + com.expediagroup + graphql-kotlin-maven-plugin + ${graphql-kotlin.version} + + + + generate-graalvm-metadata + + + com.example + com.example.ApplicationKt + + + + + + + + + + + native + + + + org.graalvm.buildtools + native-maven-plugin + ${native-maven-plugin.version} + true + + + build-native + + compile-no-fork + + package + + + + true + + --initialize-at-build-time=io.ktor,kotlin,ch.qos.logback,org.slf4j + -H:+ReportExceptionStackTraces + + + true + + + + + + + + +``` + +We need to make following changes to be able to generate GraalVM native image: + +1. Configure GraphQL Kotlin plugin to generate GraalVM metadata + +:::caution +This goal has to run AFTER `compile` but before `package` phase. It defaults to `process-classes` phase. +::: + +2. Configure [GraalVM Native Maven plugin](https://graalvm.github.io/native-build-tools/latest/maven-plugin.html) + +:::info +GraalVM recommends to create separate profile that simplifies native image creation. Alternatively you can also generate +native image by explicitly executing `native-image` goal. +::: + + + + +Once the build is configured we can then generate our native image by running `package` command with `native` profile. + +```shell +> ./mvnw -Pnative package +``` + +Native executable image will then be generated under `target` directory. + +## Spring GraalVM Native Image + +Given following schema + +```kotlin +@Component +class NativeExampleQuery : Query { + fun helloWorld() = "Hello World" +} +``` + +We first need to configure our server to avoid class scanning. Even though our example schema does not contain any +polymorphic types, **we still need to explicitly opt-out of class scanning by providing type hierarchy**. + +```kotlin +@SpringBootApplication +class Application { + @Bean + fun typeResolver(): GraphQLTypeResolver = SimpleTypeResolver(mapOf()) +} + +fun main(args: Array) { + runApplication(*args) +} +``` + +We then need to update our build with native configuration + + + + + +```xml + + + 4.0.0 + + com.example + example-graalvm-server + 1.0-SNAPSHOT + + + 17 + 1.7.22 + ${latestGraphqlKotlinVersion} + + 3.0.6 + + + + + com.expediagroup + graphql-kotlin-spring-server + ${graphql-kotlin.version} + + + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/test/kotlin + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + -Xjsr305=strict + + + spring + + ${kotlin.jvmTarget} + + + + org.jetbrains.kotlin + kotlin-maven-allopen + ${kotlin.version} + + + + + + +``` + + + + +```xml + + + 4.0.0 + + com.example + example-graalvm-server + 1.0-SNAPSHOT + + + 17 + 1.7.22 + ${latestGraphqlKotlinVersion} + + 3.0.6 + 0.9.21 + + + + + com.expediagroup + graphql-kotlin-spring-server + ${graphql-kotlin.version} + + + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/test/kotlin + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + -Xjsr305=strict + + + spring + + ${kotlin.jvmTarget} + + + + org.jetbrains.kotlin + kotlin-maven-allopen + ${kotlin.version} + + + + + + com.expediagroup + graphql-kotlin-maven-plugin + ${graphql-kotlin.version} + + + + generate-graalvm-metadata + + + com.example + com.example.ApplicationKt + + + + + + + + + + + native + + + + org.graalvm.buildtools + native-maven-plugin + ${native-maven-plugin.version} + true + + + build-native + + compile-no-fork + + package + + + + true + + true + + + + + + + + +``` + +We need to make following changes to be able to generate GraalVM native image: + +1. Configure GraphQL Kotlin plugin to generate GraalVM metadata + +:::caution +This goal has to run AFTER `compile` but before `package` phase. It defaults to `process-classes` phase. +::: + +2. Configure [GraalVM Native Maven plugin](https://graalvm.github.io/native-build-tools/latest/maven-plugin.html) + +:::info +GraalVM recommends to create separate profile that simplifies native image creation. Alternatively you can also generate +native image by explicitly executing `native-image` goal. +::: + + + + +Once the build is configured we can then generate our native image by running `package` command with `native` profile. + +```shell +> ./mvnw -Pnative package +``` + +Native executable image will then be generated under `target` directory. diff --git a/website/versioned_docs/version-7.x.x/plugins/maven-plugin-usage-sdl.md b/website/versioned_docs/version-7.x.x/plugins/maven-plugin-usage-sdl.md new file mode 100644 index 0000000000..32eeb1fdef --- /dev/null +++ b/website/versioned_docs/version-7.x.x/plugins/maven-plugin-usage-sdl.md @@ -0,0 +1,77 @@ +--- +id: maven-plugin-usage-sdl +title: Maven Plugin SDL Usage +sidebar_label: Generating SDL +--- + +GraphQL Kotlin follows a code-first approach where schema is auto generated from your source code at runtime. GraphQL Kotlin +plugins can be used to generate schema as a build time artifact. This allows you to seamlessly integrate with various +GraphQL tools that may require a schema artifact as an input (e.g. to perform backwards compatibility checks, etc). + +## Generating SDL + +GraphQL schema can be generated directly from your source code using reflections. `generate-sdl` mojo will scan your +classpath looking for classes implementing `Query`, `Mutation` and `Subscription` marker interfaces and then generates the +corresponding GraphQL schema using `graphql-kotlin-schema-generator` and default `NoopSchemaGeneratorHooks`. In order to +limit the amount of packages to scan, this mojo requires users to provide a list of `packages` that can contain GraphQL +types. + +```xml + + com.expediagroup + graphql-kotlin-maven-plugin + ${graphql-kotlin.version} + + + + generate-sdl + + + + com.example + + + + + +``` + +## Using Custom Hooks Provider + +Plugin will default to use `NoopSchemaGeneratorHooks` to generate target GraphQL schema. If your project uses custom hooks +or needs to generate the federated GraphQL schema, you will need to provide an instance of `SchemaGeneratorHooksProvider` +service provider that will be used to create an instance of your custom hooks. + +`generate-sdl` mojo utilizes [ServiceLoader](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ServiceLoader.html) +mechanism to dynamically load available `SchemaGeneratorHooksProvider` service providers from the classpath. Service provider +can be provided as part of your project, included in one of your project dependencies or through explicitly provided artifact. +See [Schema Generator Hooks Provider](./hooks-provider.mdx) for additional details on how to create custom hooks service provider. +Configuration below shows how to configure GraphQL Kotlin plugin with explicitly provided artifact to generate federated +GraphQL schema. + +```xml + + com.expediagroup + graphql-kotlin-maven-plugin + ${graphql-kotlin.version} + + + + generate-sdl + + + + com.example + + + + + + + com.expediagroup + graphql-kotlin-federated-hooks-provider + ${graphql-kotlin.version} + + + +``` diff --git a/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/advanced-features.md b/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/advanced-features.md new file mode 100644 index 0000000000..5d4ce8802a --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/advanced-features.md @@ -0,0 +1,30 @@ +--- +id: advanced-features +title: Advanced Features +--- +## Adding Custom Additional Types + +There are a couple ways you can add more types to the schema without having them be directly consumed by a type in your schema. +This may be required for [Apollo Federation](../federation/apollo-federation.mdx), or maybe adding other interface implementations that are not picked up. + +### `SchemaGenerator::generateSchema` + +When generating a schema you can optionally specify additional types and input types to be included in the schema. This will +allow you to link to those types from your custom `SchemaGeneratorHooks` implementation using GraphQL reference instead of +manually creating the underlying GraphQL type. + +```kotlin +val myConfig = SchemaGeneratorConfig(supportedPackages = listOf("com.example")) +val generator = SchemaGenerator(myConfig) + +val schema = generator.generateSchema( + queries = myQueries, + additionalTypes = setOf(MyCustomObject::class.createType()), + additionalInputTypes = setOf(MyCustomInputObject::class.createType()) +) +``` + +### `SchemaGenerator::addAdditionalTypesWithAnnotation` + +This method is protected so if you override the `SchemaGenerator` used you can call this method to add types that have a specific annotation. +You can see how this is used in `graphql-kotlin-federation` as [an example](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/generator/federation/FederatedSchemaGenerator.kt). diff --git a/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/annotations.md b/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/annotations.md new file mode 100644 index 0000000000..72fd37f546 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/annotations.md @@ -0,0 +1,14 @@ +--- +id: annotations +title: Annotations +--- +`graphql-kotlin-schema-generator` ships with a number of annotation classes to allow you to enhance your GraphQL schema +for things that can't be directly derived from Kotlin reflection. + +- [@GraphQLDescription](./documenting-schema) - Provide a description for a GraphQL field +- [@GraphQLDirective](./directives) - Registers directive on a GraphQL field +- [@GraphQLIgnore](./excluding-fields) - Exclude field from the GraphQL schema +- [@GraphQLName](./renaming-fields) - Override the name used for the type +- Kotlin built in [@Deprecated](./deprecating-schema) - Apply the GraphQL `@deprecated` directive on the field +- [@GraphQLDeprecated](./deprecating-schema) - Apply the GraphQL `@deprecated` directive but only in the schema, not in your own Kotlin code with `@Deprecated` +- [@GraphQLType](./custom-type-reference) - Allows specifying a return type that is not the Kotlin code diff --git a/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/custom-type-reference.md b/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/custom-type-reference.md new file mode 100644 index 0000000000..4c76113d0e --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/custom-type-reference.md @@ -0,0 +1,97 @@ +--- +id: custom-type-reference +title: Custom Types +--- + +Code-first has many advantages and removes duplication. However, one downside is that the types defined have to match +compiled Kotlin code. In some cases, it is possible to define a schema that is valid in SDL but it would be impossible to +return a Kotlin type that matches exactly that type. In these cases, you can pass in custom types in the schema +generator config and annotate the schema with the type info. + +A common example is when you need to return a type or union defined in library JAR, but you can not change the code. +For example, let's say there is a type in a library. You can not change the fields, add annotations, or have it implement interfaces. + +```kotlin +// Defined in external library +class Foo(val number: Int) +``` + +If you want to have this type be used in a new interface or union defined in your API, it is not possible to do in Kotlin code +since you can not modify the compiled code. + +```kotlin +// New interface +interface TypeWithNumber { val number: Int } +// New union +interface TypeWithAnyField + +// Error: We are not able to return Foo for any of these functions +fun customInterface(): TypeWithNumber = Foo(1) +fun customUnion(): TypeWithAnyField = Foo(1) +``` + +## `@GraphQLType` +You can use this annotation to change the return type of a field. The annotation accepts the type name, which will be +added as a type reference in the schema. This means that you will have to define the type and its schema with the same name in the configuration. + +Doing this could still be serialization issues, so you should make sure that the data you return from the field matches the defined schema of the type. + +```kotlin +// Defined in external library or can not be modified +class Foo(val number: Int) +class Bar(val value: String) + +// Might return Foo or Bar +@GraphQLType("FooOrBar") +fun customUnion(): Any = if (Random.nextBoolean()) Foo(1) else Bar("hello") + +// Will throw runtime error when serialized data does not match the schema +@GraphQLType("FooOrBar") +fun invalidType(): String = "hello" +``` + +### Custom Type Configuration +In our above example there is no Kotlin code for the type `FooOrBar`. It only exists by reference right now. +To add the type into the schema, specify the additional types in the [SchemaGeneratorConfiguration](./generator-config). +This is using the [grapqhl-java schema object builders](https://www.graphql-java.com/documentation/schema#union). + + +```kotlin +val fooCustom = GraphQLUnionType.newUnionType() + .name("FooOrBar") + .possibleType(GraphQLTypeReference("Foo")) + .possibleType(GraphQLTypeReference("Bar")) + .typeResolver { /* Logic for how to resolve types */ } + .build() +val config = SchemaGeneratorConfig(supportedPackages, additionalTypes = setOf(fooCustom)) +``` + +## Adding Missing Kotlin Types +In our above example, since the return type of the Kotlin code did not reference the Kotlin types `Foo` or `Bar`, +reflection will not pick those up by default. They will also need to be added as additional Kotlin types (`KType`) when generating the schema. + +```kotlin +val generator = SchemaGenerator(config) +val schema = generator.use { + it.generateSchema( + queries = listOf(TopLevelObject(Query())), + additionalTypes = setOf( + Foo::class.createType(), + Bar::class.createType(), + ) + ) +} +``` + +## Final Result +With all the above code, the final resulting schema should like this: + +```graphql +type Query { + customUnion: FooOrBar! +} + +union FooOrBar = Foo | Bar +type Foo { number: Int! } +type Bar { value: String! } +``` diff --git a/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/deprecating-schema.md b/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/deprecating-schema.md new file mode 100644 index 0000000000..a4837f6ab4 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/deprecating-schema.md @@ -0,0 +1,46 @@ +--- +id: deprecating-schema +title: Deprecating Schema +--- + +GraphQL schemas supports deprecation directive on +the fields (which correspond to Kotlin properties and functions), input fields and enum values. + +Deprecation of arguments is currently not supported [in Kotlin](https://youtrack.jetbrains.com/issue/KT-25643). + +## Kotlin.Deprecated + +Instead of creating a custom annotation, +`graphql-kotlin-schema-generator` just looks for the `@kotlin.Deprecated` annotation and will use that annotation message +for the deprecated reason. + +```kotlin +class SimpleQuery { + @Deprecated(message = "this query is deprecated", replaceWith = ReplaceWith("shinyNewQuery")) + fun simpleDeprecatedQuery(): Boolean = false + + fun shinyNewQuery(): Boolean = true +} +``` + +The above query would produce the following GraphQL schema: + +```graphql +type Query { + simpleDeprecatedQuery: Boolean! @deprecated(reason: "this query is deprecated, replace with shinyNewQuery") + + shinyNewQuery: Boolean! +} +``` + +## GraphQLDeprecated + +A side-effect of using `@Deprecated` is that it marks your own Kotlin code as being deprecated, which may not be what you want. Using `@GraphQLDeprecated` you can add the `@deprecated` directive to the GraphQL schema, but not have your Kotlin code show up as deprecated in your editor. + +```kotlin +class SimpleQuery { + @GraphQLDeprecated(message = "this query is deprecated", replaceWith = ReplaceWith("shinyNewQuery")) + fun simpleDeprecatedQuery(): Boolean = false + + fun shinyNewQuery(): Boolean = true +} diff --git a/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/directives.md b/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/directives.md new file mode 100644 index 0000000000..e351b277be --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/directives.md @@ -0,0 +1,210 @@ +--- +id: directives +title: Directives +--- +GraphQL directives can be used to transform the schema types, fields and arguments as well as modify the runtime +behavior of the query (e.g. implement access control, etc). Common use cases involve limiting functionality based on the +user authentication and authorization. While [GraphQL +spec](https://graphql.github.io/graphql-spec/draft/#sec-Type-System.Directives) specifies two types of directives - +`executable` (aka query) and `type system` (aka schema) directives, only the latter one is supported by +`graphql-kotlin-schema-generator`. + +## Default Directives + +`@deprecated` - schema directive used to represent deprecated portion of the schema. +See [@Deprecated and @GraphQLDeprecated](deprecating-schema.md) annotation documentation for more details + +```graphql +type Query { + deprecatedQuery: Boolean! @deprecated(reason: "No longer supported") +} +``` + +`@skip` - query directive that allows for conditional exclusion of fields or fragments + +```graphql +query myQuery($shouldSkip: Boolean) { + myField @skip(if: $shouldSkip) +} +``` + +`@include` - query directive that allows for conditional inclusion of fields or fragments + +```graphql +query myQuery($shouldInclude: Boolean) { + myField @include(if: $shouldInclude) +} +``` + +## Custom Directives + +Custom directives can be added to the schema using custom annotations: + +```kotlin +@GraphQLDirective( + name = "awesome", + description = "This element is great", + locations = [FIELD_DEFINITION] +) +annotation class AwesomeDirective(val value: String) + +class MyQuery { + @AwesomeDirective("cool stuff") + val somethingGreat: String = "Hello World" +} +``` + +The directive will then added to the schema as: + +```graphql +# This element is great +directive @awesome(value: String) on FIELD_DEFINITION + +type MyQuery { + somethingGreat: String @awesome("cool stuff") +} +``` + +Directives can be added to various places in the schema. See the +[graphql.introspection.Introspection.DirectiveLocation](https://github.com/graphql-java/graphql-java/blob/v13.0/src/main/java/graphql/introspection/Introspection.java#L332) +enum from `graphql-java` for a full list of valid locations. + +:::note +GraphQL directives are currently not available through introspection and you have to use SDL directly +instead (you can use convenient `print` extension function of `GraphQLSchema`). See [GraphQL +issue](https://github.com/facebook/graphql/issues/300) and corresponding [graphql-java +issue](https://github.com/graphql-java/graphql-java/issues/1017) for more details about the introspection issue. +::: + +### Naming Convention + +As described in the example above, the directive name in the schema will by default come from the +`@GraphQLDirective.name` attribute which should follow `lowerCamelCase` format. If this value is not specified, the +directive name will default to the normalized decapitalized name of the annotated annotation (eg: `awesomeDirective` in +the example above). + +### Customizing Behavior + +Directives allow you to customize the behavior of your schema based on some predefined conditions. Simplest way to +modify the default behavior of your GraphQLTypes is by providing your custom `KotlinSchemaDirectiveWiring` through +`KotlinDirectiveWiringFactory` factory used by your `SchemaGeneratorHooks`. + +Example of a directive that converts field to lowercase + +```kotlin +@GraphQLDirective(name = "lowercase", description = "Modifies the string field to lowercase") +annotation class LowercaseDirective + +class LowercaseSchemaDirectiveWiring : KotlinSchemaDirectiveWiring { + + override fun onField(environment: KotlinFieldDirectiveEnvironment): GraphQLFieldDefinition { + val field = environment.element + val originalDataFetcher: DataFetcher = environment.getDataFetcher() + + val lowerCaseFetcher = DataFetcherFactories.wrapDataFetcher( + originalDataFetcher, + BiFunction{ _, value -> value.toString().toLowerCase() } + ) + environment.setDataFetcher(lowerCaseFetcher) + return field + } +} +``` + +While you can manually apply all the runtime wirings to the corresponding GraphQL types directly in +`SchemaGeneratorHooks#onRewireGraphQLType`, we recommend the usage of our +[KotlinDirectiveWiringFactory](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/directives/KotlinDirectiveWiringFactory.kt) +to simplify the integrations. `KotlinDirectiveWiringFactory` accepts a mapping of directives to corresponding wirings or +could be extended to provide the wirings through `KotlinDirectiveWiringFactory#getSchemaDirectiveWiring` that accepts +`KotlinSchemaDirectiveEnvironment`. + +```kotlin +val queries = ... +val customWiringFactory = KotlinDirectiveWiringFactory( + manualWiring = mapOf("lowercase" to LowercaseSchemaDirectiveWiring())) +val customHooks = object : SchemaGeneratorHooks { + override val wiringFactory: KotlinDirectiveWiringFactory + get() = customWiringFactory +} +val schemaGeneratorConfig = SchemaGeneratorConfig(hooks = customHooks) +val schema = toSchema(queries = queries, config = schemaGeneratorConfig) +``` + +While providing directives on different schema elements you will be able to modify the underlying GraphQL types. Keep in +mind though that data fetchers are used to resolve the fields so only field directives (and by association their +arguments directives) can modify runtime behavior based on the context and user input. + +:::caution +`graphql-kotlin` prioritizes manual wiring mappings over the wirings provided by the `KotlinDirectiveWiringFactory#getSchemaDirectiveWiring`. +This is a different behavior than `graphql-java` which will first attempt to use `WiringFactory` and then fallback to manual overrides. +::: + +For more details please refer to the example usage of directives in our [example +app](https://github.com/ExpediaGroup/graphql-kotlin/tree/master/examples/server/spring-server). + +### Repeatable Directives + +GraphQL supports repeatable directives (e.g. Apollo federation allows developers to specify multiple `@key` directives). +By default, Kotlin does not allow applying same annotation multiple times. In order to make your directives repeatable, +you need to annotate it with `kotlin.annotation.Repeatable` annotation. + +```kotlin +@Repeatable +@GraphQLDirective(locations = [DirectiveLocation.OBJECT, DirectiveLocation.INTERFACE]) +annotation class MyRepeatableDirective(val value: String) +``` + +Generates the above directive as + +```graphql +directive @myRepeatableDirective(value: String!) repeatable on OBJECT | INTERFACE +``` + +## Directive Chaining + +Directives are applied in the order annotations are declared on the given object. Given + +```kotlin +@Directive1 +@Directive2 +fun doSomething(): String { +// does something +} +``` + +`Directive1` will be applied first followed by the `Directive2`. + +## Ignoring Directive Arguments + +Normally if you wanted to exclude a field or argument from the schema, you could use [@GraphQLIgnore](./excluding-fields.md). +However, due to reflection and kotlin limitations, the generated JVM code for interface arguments can only have annotations on getters. + +This is easily fixable though using the [`@get:` target prefix](https://kotlinlang.org/docs/reference/annotations.html#annotation-use-site-targets) +See [graphql-kotlin#763](https://github.com/ExpediaGroup/graphql-kotlin/pull/763) for more details. + +```kotlin +@GraphQLDirective +annotation class DirectiveWithIgnoredArgs( + val string: String, + + @get:GraphQLIgnore + val ignoreMe: String +) +``` + +This will generate the following schema + +```graphql +directive @directiveWithIgnoredArgs( + string: String! +) on ... +``` + +## Limitations + +GraphQL specification allows usage of any valid input objects as directive arguments. Since we rely on Kotlin annotation +functionality to define our custom directives, we are limited in what can be used as annotation parameter - only primitives (or scalars), +Strings, Enums, other annotations or an array of any of the above are supported. + +Support for input objects can be added by providing that object representation as an annotation class and then adding support +for it through custom schema generator hooks. diff --git a/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/documenting-schema.md b/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/documenting-schema.md new file mode 100644 index 0000000000..9516b2535d --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/documenting-schema.md @@ -0,0 +1,41 @@ +--- +id: documenting-schema +title: Documenting Schema +--- +Since Javadocs are not available at runtime for introspection, `graphql-kotlin-schema-generator` includes an annotation +class `@GraphQLDescription` that can be used to add schema descriptions to _any_ GraphQL schema element. The string value can be in the Markdown format. + +```kotlin +@GraphQLDescription("A useful widget") +data class Widget( + @GraphQLDescription("The widget's value that can be `null`") + val value: Int? +) + +class WidgetQuery { + @GraphQLDescription("Creates new widget for given ID") + fun widgetById(@GraphQLDescription("The special ingredient") id: Int): Widget? = Widget(id) +} +``` + +The above query would produce the following GraphQL schema: + +```graphql +schema { + query: Query +} + +type Query { + """Creates new widget for given ID""" + widgetById( + """The special ingredient""" + id: Int! + ): Widget +} + +"""A useful widget""" +type Widget { + """The widget's value that can be `null`""" + value: Int +} +``` diff --git a/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/excluding-fields.md b/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/excluding-fields.md new file mode 100644 index 0000000000..1e4b82e90d --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/excluding-fields.md @@ -0,0 +1,29 @@ +--- +id: excluding-fields +title: Excluding Fields +--- +There are two ways to ensure the GraphQL schema generation omits fields when using Kotlin reflection: + +- The first is by marking the field as non-`public` scope (`private`, `protected`, `internal`) +- The second method is by annotating the field with `@GraphQLIgnore`. + +```kotlin +class SimpleQuery { + @GraphQLIgnore + fun notPartOfSchema() = "ignore me!" + + private fun privateFunctionsAreNotVisible() = "ignored private function" + + fun doSomething(value: Int): Boolean = true +} +``` + +The above query would produce the following GraphQL schema: + +```graphql +type Query { + doSomething(value: Int!): Boolean! +} +``` + +Note that the public method `notPartOfSchema` is not included in the schema. diff --git a/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/generator-config.md b/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/generator-config.md new file mode 100644 index 0000000000..4739d86a21 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/generator-config.md @@ -0,0 +1,76 @@ +--- +id: generator-config +title: Generator Configuration & Hooks +--- + +`graphql-kotlin-schema-generator` provides a single function, `toSchema,` to generate a schema from Kotlin objects. This +function accepts four arguments: config, queries, mutations and subscriptions. + +## TopLevelObjects + +* The queries, mutations and subscriptions are a list of +[TopLevelObjects](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/TopLevelObject.kt) +and will be used to generate corresponding GraphQL root types. +* Annotated schema `TopLevelObject` will be used to generate any schema directives + +## SchemaGeneratorConfig + +The [config](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/SchemaGeneratorConfig.kt) +contains all the extra information you need to pass, including custom hooks, supported packages and name overrides. +`SchemaGeneratorConfig` has some default settings but you can override them and add custom behaviors for generating your +schema. + +- `supportedPackages` **[Required]** - List of Kotlin packages that can contain schema objects. Limits the scope of + packages that can be scanned using reflections. +- `topLevelNames` _[Optional]_ - Set the name of the top level GraphQL fields, defaults to `Query`, `Mutation` and + `Subscription` +- `hooks` _[Optional]_ - Set custom behaviors for generating the schema, see below for details. +- `dataFetcherFactory` _[Optional]_ - Sets custom behavior for generating data fetchers +- `introspectionEnabled` _[Optional]_ - Boolean flag indicating whether introspection queries are enabled, introspection queries are enabled by default +- `additionalTypes` _[Optional]_ - Set of additional GraphQL types to include when generating the schema. +- `schemaObject` _[Optional]_ - Object that contains schema directive information + +## SchemaGeneratorHooks + +Hooks are lifecycle events that are called and triggered while the schema is building that allow users to customize the +schema. + +For exact names and details of every hook, see the comments and descriptions in our latest +[javadocs](https://www.javadoc.io/doc/com.expediagroup/graphql-kotlin-schema-generator) or directly in the source file: +[SchemaGeneratorHooks.kt](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/hooks/SchemaGeneratorHooks.kt) + +As an example here is how you would write a custom hook and provide it through the configuration + +```kotlin +class MyCustomHooks : SchemaGeneratorHooks { + // Only generate functions that start with "dog" + // This would probably be better just to use @GraphQLIgnore, but this is just an example + override fun isValidFunction(function: KFunction<*>) = function.name.startsWith("dog") +} + +class Query { + fun dogSound() = "bark" + + fun catSound() = "meow" +} + +val config = SchemaGeneratorConfig(supportedPackages = listOf("org.example"), hooks = MyCustomHooks()) + +val queries = listOf(TopLevelObject(Query())) + +toSchema(queries = queries, config = config) +``` + +will generate + +```graphql +schema { + query: Query +} + +type Query { + dogSound: String! +} +``` + +Notice there is no `catSound` function. diff --git a/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/renaming-fields.md b/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/renaming-fields.md new file mode 100644 index 0000000000..2a1e1c5309 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/renaming-fields.md @@ -0,0 +1,73 @@ +--- +id: renaming-fields +title: Renaming Fields +--- +By default, the schema generator will use the simple name of the underlying class for the type names and function/property names for fields. +You can change this default behavior by annotating the target class/field with `@GraphQLName`. The following Kotlin `Widget` class +will be renamed to `MyCustomName` GraphQL type and its fields will also be renamed. + +```kotlin +@GraphQLName("MyCustomName") +data class Widget( + @GraphQLName("myCustomField") + val value: Int? +) +``` + +```graphql +type MyCustomName { + myCustomField: Int +} +``` + +## Known Issues + +Due to how we deserialize input classes, if you rename a field of an input class or an enum value you must also annotate +it with the Jackson annotation `@JsonProperty`. See [issue 493](https://github.com/ExpediaGroup/graphql-kotlin/issues/493) +for more info. + +```kotlin +data class MyInputClass( + @JsonProperty("renamedField") + @GraphQLName("renamedField") + val field1: String +) + +// GraphQL enums should use UPPER_CASE naming if possible, but any case is supported +enum class Selection { + + @JsonProperty("first") + @GraphQLName("first") + ONE, + + @JsonProperty("second") + @GraphQLName("second") + TWO +} + +class QueryClass { + fun parseData(arg: MyInputClass) = "You sent ${arg.field1}" + + fun chooseValue(selection: Selection): String = when (selection) { + Selection.ONE -> "You chose the first value" + Selection.TWO -> "You chose the second value" + } +} +``` + +```graphql +input MyInputClassInput { + # This only works if both @JsonProperty and @GraphQLName are present + renamedField: String! +} + +enum Selection { + first, + second +} + +type Query { + parseData(arg: MyInputClass!): String! + chooseValue(selection: Selection!): String! +} +``` diff --git a/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/restricting-input-output.md b/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/restricting-input-output.md new file mode 100644 index 0000000000..f2eea65f64 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/customizing-schemas/restricting-input-output.md @@ -0,0 +1,29 @@ +--- +id: restricting-input-output +title: Restricting Input and Output Types +--- + +Since we are using Kotlin classes to represent both GraphQL input and output objects we can use the same class for both and the generator will handle type conflicts. + +If you want to enforce that a type should never be used as an input or output you can use the `@GraphQLValidObjectLocations` annotation. +If the class was used in the schema in an invalid location an exception will be thrown. + +```kotlin +class SimpleClass(val value: String) + +@GraphQLValidObjectLocations([Locations.INPUT_OBJECT]) +class InputOnly(val value: String) + +@GraphQLValidObjectLocations([Locations.OBJECT]) +class OutputOnly(val value: String) + +// Valid Usage +fun output1() = SimpleClass("foo") +fun output2() = OutputOnly("foo") +fun input1(input: SimpleClass) = "value was ${input.value}" +fun input2(input: InputOnly) = "value was ${input.value}" + +// Throws Exception +fun output3() = InputOnly("foo") +fun input3(input: OutputOnly) = "value was ${input.value}" +``` diff --git a/website/versioned_docs/version-7.x.x/schema-generator/execution/async-models.md b/website/versioned_docs/version-7.x.x/schema-generator/execution/async-models.md new file mode 100644 index 0000000000..386df7b8be --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/execution/async-models.md @@ -0,0 +1,151 @@ +--- +id: async-models +title: Async Models +--- +By default, `graphql-kotlin-schema-generator` will resolve all functions synchronously, i.e. it will block the +underlying thread while executing the target function. While you could configure your GraphQL server with execution +strategies that execute each query in parallel on some thread pools, instead we highly recommend to utilize asynchronous +programming models. + +## Coroutines + +`graphql-kotlin-schema-generator` has built-in support for Kotlin coroutines. Provided default +[FunctionDataFetcher](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/execution/FunctionDataFetcher.kt) +will automatically asynchronously execute suspendable functions and convert the result to `CompletableFuture` expected +by `graphql-java`. + +Example + +```kotlin +data class User(val id: String, val name: String) + +class Query { + suspend fun getUser(id: String): User { + // Your coroutine logic to get user data + } +} +``` + +will produce the following schema + +```graphql +type Query { + getUser(id: String!): User +} + +type User { + id: String! + name: String! +} +``` + +### Structured Concurrency + +`graphql-java` relies on `CompletableFuture` for asynchronous execution of the incoming requests. `CompletableFuture` is +unaware of any contextual information which means we have to rely on additional mechanism to propagate the coroutine context. +`graphql-java` v17 introduced `GraphQLContext` map as the default mechanism to propagate the contextual information about +the request. In order to preserve coroutine context, we need to populate `GraphQLContext` map with a `CoroutineScope` that +should be used to execute any suspendable functions. + +```kotlin +val graphQLExecutionScope = CoroutineScope(coroutineContext + SupervisorJob()) +val contextMap = mapOf( + CoroutineScope::class to graphQLExecutionScope +) + +val executionInput = ExecutionInput.newExecutionInput() + .graphQLContext(contextMap) + .query(queryString) + .build() +graphql.executeAsync(executionInput) +``` + +:::info +`graphql-kotlin-server` automatically populates `GraphQLContext` map with appropriate coroutine scope. Users can customize +the coroutine context by providing `CoroutineContext::class` entry in custom context using `GraphQLContextFactory`. +::: + +## CompletableFuture + +`graphql-java` relies on Java `CompletableFuture` for asynchronously processing the requests. In order to simplify the +interop with `graphql-java`, `graphql-kotlin-schema-generator` has a built-in hook which will automatically unwrap a +`CompletableFuture` and use the inner class as the return type in the schema. + +```kotlin +data class User(val id: String, val name: String) + +class Query { + fun getUser(id: String): CompletableFuture { + // Your logic to get data asynchronously + } +} +``` + +will result in the exactly the same schema as in the coroutine example above. + +## RxJava/Reactor + +If you want to use a different monad type, like `Single` from [RxJava](https://github.com/ReactiveX/RxJava) or `Mono` from +[Project Reactor](https://projectreactor.io/), you have to: + +1. Create custom `SchemaGeneratorHook` that implements `willResolveMonad` to provide the necessary logic + to correctly unwrap the monad and return the inner class to generate valid schema + +```kotlin +class MonadHooks : SchemaGeneratorHooks { + override fun willResolveMonad(type: KType): KType = when (type.classifier) { + Mono::class -> type.arguments.firstOrNull()?.type + else -> type + } ?: type +} +``` + +2. Provide custom data fetcher that will properly process those monad types. + +```kotlin +class CustomFunctionDataFetcher(target: Any?, fn: KFunction<*>, objectMapper: ObjectMapper) : FunctionDataFetcher(target, fn, objectMapper) { + override fun get(environment: DataFetchingEnvironment): Any? = when (val result = super.get(environment)) { + is Mono<*> -> result.toFuture() + else -> result + } +} + +class CustomDataFetcherFactoryProvider( + private val objectMapper: ObjectMapper +) : SimpleKotlinDataFetcherFactoryProvider(objectMapper) { + + override fun functionDataFetcherFactory(target: Any?, kFunction: KFunction<*>): DataFetcherFactory = DataFetcherFactory { + CustomFunctionDataFetcher( + target = target, + fn = kFunction, + objectMapper = objectMapper) + } +} +``` + +With the above you can then create your schema as follows: + +```kotlin +class ReactorQuery { + fun asynchronouslyDo(): Mono = Mono.just(1) +} + +val configWithReactorMonoMonad = SchemaGeneratorConfig( + supportedPackages = listOf("myPackage"), + hooks = MonadHooks(), + dataFetcherFactoryProvider = CustomDataFetcherFactoryProvider()) + +toSchema(queries = listOf(TopLevelObject(ReactorQuery())), config = configWithReactorMonoMonad) +``` + +This will produce + +```graphql +type Query { + asynchronouslyDo: Int +} +``` + +You can find additional example on how to configure the hooks in our [unit +tests](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-schema-generator/src/test/kotlin/com/expediagroup/graphql/generator/SchemaGeneratorAsyncTests.kt) +and [example app](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/examples/spring/src/main/kotlin/com/expediagroup/graphql/examples/query/AsyncQuery.kt). diff --git a/website/versioned_docs/version-7.x.x/schema-generator/execution/contextual-data.md b/website/versioned_docs/version-7.x.x/schema-generator/execution/contextual-data.md new file mode 100644 index 0000000000..573f230f93 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/execution/contextual-data.md @@ -0,0 +1,30 @@ +--- +id: contextual-data +title: Contextual Data +--- + +All GraphQL servers have a concept of a "context". A GraphQL context contains metadata that is useful to the GraphQL +server, but shouldn't necessarily be part of the GraphQL schema. A prime example of something that is appropriate +for the GraphQL context would be trace headers for an OpenTracing system such as +[Haystack](https://expediadotcom.github.io/haystack). The GraphQL query does not need the information to perform +its function, but the server needs the information to ensure observability. + +The contents of the GraphQL context vary across applications and it is up to the GraphQL server developers to decide +what it should contain. `graphql-kotlin-server` provides a simple mechanism to build a context per operation with the +[GraphQLContextFactory](../../server/graphql-context-factory.md). +If a custom factory is defined, it will then be used to populate GraphQL context based on the incoming request and make +it available during execution. + +## GraphQL Context Map +In graphql-java v17 a new context map was added to the `DataFetchingEnvironment`. This is now the way of saving info for execution, and +you can access this map through the [DataFetchingEnvironment](./data-fetching-environment.md). + +```kotlin +class ContextualQuery : Query { + fun contextualQuery( + dataFetchingEnvironment: DataFetchingEnvironment, + value: Int + ): String = + "The custom value was ${dataFetchingEnvironment.graphQLContext.get("foo")} and the value was $value" +} +``` diff --git a/website/versioned_docs/version-7.x.x/schema-generator/execution/data-fetching-environment.md b/website/versioned_docs/version-7.x.x/schema-generator/execution/data-fetching-environment.md new file mode 100644 index 0000000000..6e2845ef29 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/execution/data-fetching-environment.md @@ -0,0 +1,47 @@ +--- +id: data-fetching-environment +title: Data Fetching Environment +--- +Each resolver has access to a `DataFetchingEnvironment` that provides additional information about the currently executed query including information about what data is requested +as well as details about current execution state. For more details on the `DataFetchingEnvironment` please refer to [graphql-java documentation](https://www.graphql-java.com/documentation/v14/data-fetching/) + +You can access this info by including the `DataFetchingEnvironment` as one of the arguments to a Kotlin function. This argument will be automatically populated and injected +during the query execution but will not be included in the schema definition. + +```kotlin +class Query { + fun printEnvironmentInfo(parentField: String): MyObject = MyObject() +} + +class MyObject { + fun printParentField(childField: String, environment: DataFetchingEnvironment): String { + val parentField = environment.executionStepInfo.parent.getArgument("parentField") + return "The parentField was $parentField and the childField was $childField" + } +} +``` + +This will produce the following schema + +```graphql +type Query { + printEnvironmentInfo(parentField: String!): MyObject! +} + +type MyObject { + printParentField(childField: String!): String! +} +``` + +Then the following query would return `"The parentField was foo and the childField was bar"` + +```graphql +{ + printEnvironmentInfo(parentField: "foo") { + printParentField(childField: "bar") + } +} +``` + +You can also use this to retrieve arguments and query information from higher up the query chain. You can see a working +example in the `graphql-kotlin-spring-example` module [[link](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/examples/spring/src/main/kotlin/com/expediagroup/graphql/examples/query/EnvironmentQuery.kt)]. diff --git a/website/versioned_docs/version-7.x.x/schema-generator/execution/exceptions.md b/website/versioned_docs/version-7.x.x/schema-generator/execution/exceptions.md new file mode 100644 index 0000000000..faa64fb455 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/execution/exceptions.md @@ -0,0 +1,37 @@ +--- +id: exceptions +title: Exceptions and Partial Data +--- +## Returning GraphQL Errors + +Exceptions thrown during execution of an operation will result in an empty data response and a GraphQLError that is added to a list of errors of the result. +See [graphql-java documentation](https://www.graphql-java.com/documentation/execution#exceptions-while-fetching-data) for more details on how to customize your exception handling. + +```kotlin +fun getRandomNumberOrError(): Int { + val num = Random().nextInt(100) + return if (num <= 50) num else throw Exception("number is greater than 50") +} +``` + +## Returning Data and Errors + +GraphQL allows you to return both data and errors in a single response, as long as the data returned still matches the schema. Depending on the criticality of the encountered error, instead of throwing an exception, you may want to return +default data or use a nullable field, but still include more information in the `errors` block. In Kotlin, functions return only a single value, which means that in order to return both data +and errors you have to explicitly return them wrapped in a `DataFetcherResult` object. + +```kotlin +class DataAndErrorsQuery { + fun returnDataAndErrors(): DataFetcherResult { + val data: String? = getData() + val error = if (data == null) MyError() else null + + return DataFetcherResult.newResult() + .data(data) + .error(error) + .build() + } +} +``` + +An example of a query returning partial data is available in our [spring example app](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/examples/server/spring-server/src/main/kotlin/com/expediagroup/graphql/examples/server/spring/query/DataAndErrorsQuery.kt). diff --git a/website/versioned_docs/version-7.x.x/schema-generator/execution/fetching-data.md b/website/versioned_docs/version-7.x.x/schema-generator/execution/fetching-data.md new file mode 100644 index 0000000000..a3ac043328 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/execution/fetching-data.md @@ -0,0 +1,57 @@ +--- +id: fetching-data +title: Fetching Data +--- +Each field exposed in the GraphQL schema has a corresponding resolver (aka data fetcher) associated with it. `graphql-kotlin-schema-generator` generates the GraphQL schema +directly from the source code, automatically mapping all the fields either to use +[FunctionDataFetcher](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/execution/FunctionDataFetcher.kt) +to resolve underlying functions or the [PropertyDataFetcher](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/execution/PropertyDataFetcher.kt) +to read a value from an underlying Kotlin property. + +While all the fields in a GraphQL schema are resolved independently to produce a final result, whether a field is backed by a function or a property can have significant +performance repercussions. For example, given the following schema: + +```graphql +type Query { + product(id: ID!): Product +} + +type Product { + id: ID! + name: String! + reviews: [Review!]! +} + +type Review { + id: ID! + text: String! +} +``` + +We can define `Product` as + +```kotlin +data class Product(val id: ID, val name: String, reviews: List) +``` + +or + +```kotlin +class Product(val id: ID, val name: String) { + suspend fun reviews(): List { + // logic to fetch reviews here + } +} +``` + +If we expose the `reviews` field as a property it will always be populated regardless whether or not your client actually asks for it. On the other hand if `reviews` is backed +by a function, it will only be called if your client asks for this data. In order to minimize the over-fetching of data from your underlying data sources we recommend to +expose all your GraphQL fields that require some additional computations through functions. + +### Customizing Default Behavior + +You can provide your own custom data fetchers to resolve functions and properties by providing an instance of +[KotlinDataFetcherFactoryProvider](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/execution/KotlinDataFetcherFactoryProvider.kt#L31) +to your [SchemaGeneratorConfig](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/SchemaGeneratorConfig.kt). + +See our [spring example app](https://github.com/ExpediaGroup/graphql-kotlin/tree/master/examples/server/spring-server) for an example of `CustomDataFetcherFactoryProvider`. diff --git a/website/versioned_docs/version-7.x.x/schema-generator/execution/introspection.md b/website/versioned_docs/version-7.x.x/schema-generator/execution/introspection.md new file mode 100644 index 0000000000..814f9c5ea6 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/execution/introspection.md @@ -0,0 +1,46 @@ +--- +id: introspection +title: Introspection +--- +By default, GraphQL servers expose a built-in system, called **introspection**, that exposes details about the underlying schema. +Clients can use introspection to obtain information about all the supported queries as well as all the types exposed in the schema. + +## Introspection types + +- _\_\_schema_ - root level query field that provides information about all entry points (e.g. `queryType`), all types exposed + by the schema (including built-in scalars and introspection types) as well as all directives supported by the system +- _\_\_type(name: String!)_ - root level query field that provides information about the requested type (if it exists) +- **_typename_** - field that can be added to _ANY_ selection and will return the name of the enclosing type, + is often used in polymorphic queries in order to easily determine underlying implementation type +- **_Directive, DirectiveLocation, EnumValue, Field, InputValue, Schema, Type, TypeKind_** - built-in + introspection types that are used to describe the schema. + +For example, the query below will return a root Query object name as well as names of all types and all directives. + +```graphql +query { + __schema { + queryType { + name + } + types { + name + } + directives { + name + } + } +} +``` + +Additional information on introspection can be found on [GraphQL.org](https://graphql.org/learn/introspection/). + +## Disabling Introspection + +Introspection system can be disabled by specifying `introspectionEnabled=false` configuration option on an instance of +`SchemaGeneratorConfig` that will be used by the `SchemaGenerator` to generate the GraphQL schema. + +Many GraphQL tools (e.g. [GraphQL Playground](https://github.com/prisma-labs/graphql-playground) or [GraphiQL](https://github.com/graphql/graphiql)) +rely on introspection queries to function properly. Disabling introspection will prevent clients from accessing `__schema` +and `__type` fields. This may break some of the functionality that your clients might rely on and should be used with +extreme caution. diff --git a/website/versioned_docs/version-7.x.x/schema-generator/execution/optional-undefined-arguments.md b/website/versioned_docs/version-7.x.x/schema-generator/execution/optional-undefined-arguments.md new file mode 100644 index 0000000000..8504e2f227 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/execution/optional-undefined-arguments.md @@ -0,0 +1,75 @@ +--- +id: optional-undefined-arguments +title: Optional Undefined Arguments +--- +In the GraphQL world, input types can be optional which means that the client can either: + +- Not specify a value at all +- Send null explicitly +- Send a non-null value + +This is in contrast with the JVM world where objects can either have some specific value or don't have any value (i.e. +are `null`). As a result, when using default serialization logic it is not possible to distinguish between missing/unspecified +value and explicit `null` value. + +## Using OptionalInput wrapper + +`OptionalInput` is a convenient sealed class wrapper that provides distinction between undefined, null, and non-null +values. If the argument is not specified in the request it will be represented as a `OptionalInput.Undefined` object, otherwise the +value will be wrapped in `OptionalInput.Defined` class. As a best practice, we highly recommend to set appropriate +[default values to all optional arguments](https://opensource.expediagroup.com/graphql-kotlin/docs/schema-generator/writing-schemas/arguments#default-values). + +```kotlin +fun optionalInput(input: OptionalInput = OptionalInput.Undefined): String = when (input) { + is OptionalInput.Undefined -> "input was not specified" + is OptionalInput.Defined -> "input value: ${input.value}" +} +``` + +```graphql +query OptionalInputQuery { + undefined: optionalInput # input was not specified + null: optionalInput(value: null) # input value: null + foo: optionalInput(value: "foo") # input value: foo +} +``` + +:::info +Regardless whether the generic type of `OptionalInput` is specified as nullable or not it will always result in a nullable +value in `Defined` class, i.e. `OptionalInput` will appear as nullable `String` in the GraphQL schema and in the wrapped value. +::: + +## Using DataFetchingEnvironment + +Optional input types can be represented as nullable parameters in Kotlin + +```kotlin +fun optionalInput(value: String? = null): String? = value +``` + +```graphql +query OptionalInputQuery { + undefined: optionalInput # null + null: optionalInput(value: null) # null + foo: optionalInput(value: "foo") # foo +} +``` + +By default, if an optional input value is not specified, then the execution engine will fallback to the argument default +value (in our example above `null`). This means that you can not tell, by just the value alone, whether the request did +not contain any argument or the client explicitly passed in the default value. + +Instead, you can inspect all passed in arguments using the [DataFetchingEnvironment](./data-fetching-environment.md). + +```kotlin +fun optionalInput(value: String? = null, dataFetchingEnvironment: DataFetchingEnvironment): String = + if (dataFetchingEnvironment.containsArgument("value")) { + "The value was $value" + } else { + "The value was undefined" + } +``` + +## Kotlin Default Values + +If you don't need logic for when the client specified a value, you can still use [Kotlin default values](../writing-schemas/arguments.md) diff --git a/website/versioned_docs/version-7.x.x/schema-generator/execution/subscriptions.md b/website/versioned_docs/version-7.x.x/schema-generator/execution/subscriptions.md new file mode 100644 index 0000000000..be5598633d --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/execution/subscriptions.md @@ -0,0 +1,63 @@ +--- +id: subscriptions +title: Subscriptions +--- +Subscriptions are supported with `graphql-java`. See their documentation first: + +https://www.graphql-java.com/documentation/subscriptions + +To make a function a subscription function you just have to have the return type wrapped in an implementation of a +reactive-streams `Publisher`. As an example, here is a function that uses Spring WebFlux to return a random number every +second. Since `Flux` is an implementation of `Publisher` this is a valid method. + +```kotlin +fun counter(): Flux = Flux.interval(Duration.ofSeconds(1)).map { Random.nextInt() } +``` + +Then in the `toSchema` method you just have to provide a `List` the same way as queries and mutations +are provided with the `subscriptions` argument. + +```kotlin +toSchema( + config = schemaConfig, + queries = queries.toTopLevelObjects(), + mutations = mutations.toTopLevelObjects(), + subscriptions = subscriptions.toTopLevelObjects() +) +``` + +## Flow Support + +`graphql-kotlin` provides support for Kotlin `Flow` through `FlowSubscriptionSchemaGeneratorHooks` and `FlowSubscriptionExecutionStrategy`. +Both hooks and execution strategy have to be configured in order to support `Flow` in your GraphQL server. + +`FlowSubscriptionSchemaGeneratorHooks` are custom hooks that provide support for using `Flow` return type within the +GraphQL server. + +`FlowSubscriptionExecutionStrategy` is a reimplementation of the `graphql-java` default `SubscriptionExecutionStrategy` +that adds support for handling Kotlin `Flow` types. Thanks to the Kotlin coroutines interoperability, this strategy works +with any `Publisher` and will automatically convert any `Flow`s to a `Publisher`. + +## Subscription Hooks + +### `willResolveMonad` + +This hooks is called before resolving Kotlin return type to a GraphQL type and can be used to provide support for additional +monads (e.g. Kotlin `Flow`). + +### `didGenerateSubscriptionType` +This hook is called after a new subscription type is generated but before it is added to the schema. The other generator +hooks are still called so you can add logic for the types and validation of subscriptions the same as queries and mutations. + +### `isValidSubscriptionReturnType` +This hook is called when generating the functions for each subscription. It allows for changing the rules of what classes +can be used as the return type. By default, graphql-java supports `org.reactivestreams.Publisher`. + +To effectively use this hook, you should also override the `willResolveMonad` hook to support the additional subscription +return type. Your GraphQL server may also require a custom subscription execution strategy in order to process it at runtime. + +## Server Implementation + +The server that runs your GraphQL schema will have to support some method for subscriptions, like WebSockets. +`graphql-kotlin-spring-server` provides a default WebSocket based implementation. See more details in the +[server documentation](../../server/server-subscriptions.md). diff --git a/website/versioned_docs/version-7.x.x/schema-generator/federation/apollo-federation.mdx b/website/versioned_docs/version-7.x.x/schema-generator/federation/apollo-federation.mdx new file mode 100644 index 0000000000..61a06bae90 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/federation/apollo-federation.mdx @@ -0,0 +1,149 @@ +--- +id: apollo-federation +title: Apollo Federation +--- + + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +In many cases, exposing single GraphQL API that exposes unified view of all the available data provides tremendous value +to their clients. As the underlying graph scales, managing single monolithic GraphQL server might become less and less +feasible making it much harder to manage and leading to unnecessary bottlenecks. Migrating towards federated model with +an API gateway and a number of smaller GraphQL services behind it alleviates some of those problems and allows teams to +scale their graphs more easily. + +[Apollo Federation](https://www.apollographql.com/docs/federation/) is an architecture for composing multiple GraphQL +services into a single graph. Federated schemas rely on a number of custom directives to instrument the behavior of the +underlying graph and convey the relationships between different schema types. Each individual GraphQL server generates a +valid GraphQL schema and can be run independently. This is in contrast with a traditional schema stitching approach where +relationships between individual services, i.e. linking configuration, is configured at the GraphQL gateway level. + +## Federation v1 vs Federation v2 + +Federation v2 is an evolution of the Federation spec to make it more powerful, flexible and easier to adapt. While v1 and +v2 schemas are similar in many ways, Federation v2 relaxes some of the constraints and adds additional capabilities. See +[Apollo documentation](https://www.apollographql.com/docs/federation/federation-2/new-in-federation-2/) for details. + +By default, `graphql-kotlin-federation` library will generate Federation v2 compatible schema. In order to generate v1 +compatible schema you have to explicitly opt-out by specifying `optInFederationV2 = false` on your instance of +`FederatedSchemaGeneratorHooks`. + +```kotlin +val myHooks = FederatedSchemaGeneratorHooks(resolvers = myFederatedResolvers) +val myConfig = FederatedSchemaGeneratorConfig( + supportedPackages = "com.example", + hooks = myHooks +) + +toFederatedSchema( + config = myConfig, + queries = listOf(TopLevelObject(MyQuery())) +) +``` + +:::note +When generating federated schemas, `graphql-kotlin-spring-server` defaults to Federation v2. If you want to generate Federation +v1 schema, you have to explicitly opt-out by configuring `graphql.federation.optInV2 = false` property. +::: + +## Install + +Using a JVM dependency manager, link `graphql-kotlin-federation` to your project. + + + + + +```kotlin +implementation("com.expediagroup", "graphql-kotlin-federation", latestVersion) +``` + + + + +```xml + + com.expediagroup + graphql-kotlin-federation + ${latestVersion} + +``` + + + + +## Usage + +`graphql-kotlin-federation` is build on top of `graphql-kotlin-schema-generator` and adds a few extra methods and class to use to generate federation compliant schemas. + +### `toFederatedSchema` + +Just like the basic [toSchema](../schema-generator-getting-started.mdx), `toFederatedSchema` accepts five parameters: `config`, `queries`, `mutations`, `subscriptions` and `schemaObject`. +The difference is that the `config` class is of type [FederatedSchemaGeneratorConfig](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/generator/federation/FederatedSchemaGeneratorConfig.kt). +This class extends the [base configuration class](../customizing-schemas/generator-config.md) and adds some default logic. You can override the logic if needed, but do so with caution as you may no longer generate a spec compliant schema. + +You can see the definition for `toFederatedSchema` [in the +source](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/generator/federation/toFederatedSchema.kt). + +### Example + +```kotlin +@KeyDirective(fields = FieldSet("id")) +data class User( + val id: ID, + val name: String +) + +class Query { + fun getUsers(): List = getUsersFromDB() +} + +val config = FederatedSchemaGeneratorConfig( + supportedPackages = "com.example", + hooks = FederatedSchemaGeneratorHooks(emptyList()) +) + +toFederatedSchema( + config = config, + queries = listOf(TopLevelObject(Query())) +) +``` + +will generate + +```graphql +schema @link(import : ["@key", "FieldSet"], url : "https://specs.apollo.dev/federation/v2.6"){ + query: Query +} + +directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE +directive @link(import: [String], url: String!) repeatable on SCHEMA + +type Query { + getUsers: [User!]! + + _entities(representations: [_Any!]!): [_Entity]! + _service: _Service! +} + +type User @key(fields : "id", resolvable : true) { + id: ID! + name: String! +} + +union _Entity = User + +type _Service { + sdl: String! +} + +scalar FieldSet +scalar _Any +``` diff --git a/website/versioned_docs/version-7.x.x/schema-generator/federation/federated-directives.md b/website/versioned_docs/version-7.x.x/schema-generator/federation/federated-directives.md new file mode 100644 index 0000000000..d71fa9dd77 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/federation/federated-directives.md @@ -0,0 +1,686 @@ +--- +id: federated-directives +title: Federated Directives +--- +`graphql-kotlin` supports a number of directives that can be used to annotate a schema and direct certain behaviors. + +For more details, see the [Apollo Federation Specification](https://www.apollographql.com/docs/federation/subgraph-spec/). + +## `@authenticated` directive + +```graphql +directive @authenticated on + ENUM + | FIELD_DEFINITION + | INTERFACE + | OBJECT + | SCALAR +``` + +Directive that is used to indicate that the target element is accessible only to the authenticated supergraph users. For more granular access control, see the +[`@requiresScopes`[#requirescope-directive] directive usage. Refer to the [Apollo Router documentation](https://www.apollographql.com/docs/router/configuration/authorization#authenticated) +for additional details. + +## `@composeDirective` directive + +```graphql +directive @composeDirective(name: String!) repeatable on SCHEMA +``` + +By default, Supergraph schema excludes all custom directives. The `@composeDirective` is used to specify custom directives that should be exposed in the Supergraph schema. + +In order to use composed directive, you subgraph needs to +1. contain your custom directive definition +2. import your custom directive from a corresponding link spec +3. apply `@composeDirective` with custom directive name on your schema + +Example: +Given `@custom` directive we can preserve it in the Supergraph schema + +```kotlin +// 1. directive definition +@GraphQLDirective(name = "custom", locations = [Introspection.DirectiveLocation.FIELD_DEFINITION]) +annotation class CustomDirective + +@LinkDirective(url = "https://myspecs.dev/myCustomDirective/v1.0", import = ["@custom"]) // 2. import custom directive from a spec +@ComposeDirective(name = "custom") // 3. apply @composeDirective to preserve it in the schema +class CustomSchema + +class SimpleQuery { + @CustomDirective + fun helloWorld(): String = "Hello World" +} +``` + +it will generate following schema + +```graphql +schema +@composeDirective(name: "@custom") +@link(import : ["@custom"], url: "https://myspecs.dev/myCustomDirective/v1.0") +@link(url : "https://specs.apollo.dev/federation/v2.5") +{ + query: Query +} + +directive @custom on FIELD_DEFINITION + +type Query { + helloWorld: String! @custom +} +``` + +See [@composeDirective definition](https://www.apollographql.com/docs/federation/federated-types/federated-directives/#composedirective) for more information. + +## `@contact` directive + +```graphql +directive @contact( + "Contact title of the subgraph owner" + name: String! + "URL where the subgraph's owner can be reached" + url: String + "Other relevant notes can be included here; supports markdown links" + description: String +) on SCHEMA +``` + +Contact schema directive can be used to provide team contact information to your subgraph schema. This information is automatically parsed and displayed by Apollo Studio. +See [Subgraph Contact Information](https://www.apollographql.com/docs/studio/federated-graphs/#subgraph-contact-info) for additional details. + +#### Example usage on the schema class: + +```kotlin +@ContactDirective( + name = "My Team Name", + url = "https://myteam.slack.com/archives/teams-chat-room-url", + description = "send urgent issues to [#oncall](https://yourteam.slack.com/archives/oncall)." +) +class MySchema +``` + +will generate + +```graphql +schema @contact(description : "send urgent issues to [#oncall](https://yourteam.slack.com/archives/oncall).", name : "My Team Name", url : "https://myteam.slack.com/archives/teams-chat-room-url"){ + query: Query +} +``` + +## `@extends` directive + +:::caution +**`@extends` directive is deprecated**. Federation v2 no longer requires `@extends` directive due to the smart entity type +merging. All usage of `@extends` directive should be removed from your Federation v2 schemas. +::: + +```graphql +directive @extends on OBJECT | INTERFACE +``` + +`@extends` directive is used to represent type extensions in the schema. Native type extensions are currently +unsupported by the `graphql-kotlin` libraries. Federated extended types should have corresponding `@key` directive +defined that specifies primary key required to fetch the underlying object. + +#### Example + +```kotlin +@KeyDirective(FieldSet("id")) +@ExtendsDirective +class Product(@ExternalDirective val id: String) { + fun newFunctionality(): String = "whatever" +} +``` + +will generate + +```graphql +type Product @key(fields : "id") @extends { + id: String! @external + newFunctionality: String! +} +``` + +## `@external` directive + +```graphql +# federation v1 definition +directive @external on FIELD_DEFINITION + +# federation v2 definition +directive @external on OBJECT | FIELD_DEFINITION +``` + +The `@external` directive is used to mark a field as owned by another service. This allows service A to use fields from +service B while also knowing at runtime the types of that field. All the external fields should either be referenced from +the `@key`, `@requires` or `@provides` directives field sets. + +Due to the smart merging of entity types, Federation v2 no longer requires `@external` directive on `@key` fields and can +be safely omitted from the schema. `@external` directive is only required on fields referenced by the `@requires` and +`@provides` directive. + +#### Example + +```kotlin +@KeyDirective(FieldSet("id")) +class Product(val id: String) { + @ExternalDirective + var externalField: String by Delegates.notNull() + + @RequiresDirective(FieldSet("externalField")) + fun newFunctionality(): String { ... } +} +``` + +will generate + +```graphql +type Product @key(fields : "id") { + externalField: String! @external + id: String! + newFunctionality: String! +} +``` + +## `@inaccessible` directive + +:::note +Only available in Federation v2. +::: + +```graphql +directive @inaccessible on FIELD_DEFINITION + | OBJECT + | INTERFACE + | UNION + | ENUM + | ENUM_VALUE + | SCALAR + | INPUT_OBJECT + | INPUT_FIELD_DEFINITION + | ARGUMENT_DEFINITION +``` + +Inaccessible directive marks location within schema as inaccessible from the GraphQL Gateway. While `@inaccessible` fields are not exposed by the gateway to the clients, +they are still available for query plans and can be referenced from `@key` and `@requires` directives. This allows you to not expose sensitive fields to your clients but +still make them available for computations. Inaccessible can also be used to incrementally add schema elements (e.g. fields) to multiple subgraphs without breaking composition. + +See [@inaccessible specification](https://specs.apollo.dev/inaccessible/v0.2) for additional details. + +:::caution +Location within schema will be inaccessible from the GraphQL Gateway as long as **ANY** of the subgraphs marks that location as `@inacessible`. +::: + +#### Example + +```kotlin +class Product( + val id: String, + @InaccessibleDirective + val secret: String +) +``` + +will be generated by the subgraph as + +```graphql +type Product { + id: String! + secret: String! @inaccessible +} +``` + +but will be exposed on the GraphQL Gateway as + +```graphql +type Product { + id: String! +} +``` + +## `@interfaceObject` directive + +:::note +Only available in Federation v2. +::: + +```graphql +directive @interfaceObject on OBJECT +``` + +This directive provides meta information to the router that this entity type defined within this subgraph is an interface in the supergraph. This allows you to extend functionality +of an interface across the supergraph without having to implement (or even be aware of) all its implementing types. + +Example: +Given an interface that is defined somewhere in our supergraph + +```graphql +interface Product @key(fields: "id") { + id: ID! + description: String +} + +type Book implements Product @key(fields: "id") { + id: ID! + description: String + pages: Int! +} + +type Movie implements Product @key(fields: "id") { + id: ID! + description: String + duration: Int! +} +``` + +We can extend `Product` entity in our subgraph and a new field directly to it. This will result in making this new field available to ALL implementing types. + +```kotlin +@InterfaceObjectDirective +@KeyDirective(fields = FieldSet("id")) +data class Product(val id: ID) { + fun reviews(): List = TODO() +} +``` + +Which generates the following subgraph schema + +```graphql +type Product @key(fields: "id") @interfaceObject { + id: ID! + reviews: [Review!]! +} +``` + +## `@key` directive + +```graphql +# federation v1 definition +directive @key(fields: _FieldSet!) repeatable on OBJECT | INTERFACE + +# federation v2 definition +directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE +``` + +The `@key` directive is used to indicate a combination of fields that can be used to uniquely identify and fetch an +object or interface. The specified field set can represent single field (e.g. `"id"`), multiple fields (e.g. `"id name"`) or +nested selection sets (e.g. `"id user { name }"`). Multiple keys can be specified on a target type. + +Key directives should be specified on all entities (objects that can resolve its fields across multiple subgraphs). Key +fields specified in the directive field set should correspond to a valid field on the underlying GraphQL interface/object. + +#### Basic Example + +```kotlin +@KeyDirective(FieldSet("id")) +@KeyDirective(FieldSet("upc")) +class Product(val id: String, val upc: String, val name: String) +``` + +will generate + +```graphql +type Product @key(fields: "id") @key(fields: "upc") { + id: String! + name: String! + upc: String! +} +``` + +#### Referencing External Entities + +Entity types can be referenced from other subgraphs without contributing any additional fields, i.e. we can update type within our schema with a reference to a federated type. In order to generate +a valid schema, we need to define **stub** for federated entity that contains only key fields and also mark it as not resolvable within our subgraph. For example, if we have `Review` entity defined +in our supergraph, we can reference it in our product schema using following code + +```kotlin +@KeyDirective(fields = FieldSet("id")) +class Product(val id: String, val name: String, val reviews: List) + +// review stub referencing just the key fields +@KeyDirective(fields = FieldSet("id"), resolvable = false) +class Review(val id: String) +``` + +which will generate + +```graphql +type Product @key(fields: "id") { + id: String! + name: String! + reviews: [Review!]! +} + +type Review @key(fields: "id", resolvable: false) { + id: String! +} +``` + +This allows end users to query GraphQL Gateway for any product review fields and they will be resolved by calling the appropriate subgraph. + +## `@link` directive + +:::note +Only available in Federation v2. +::: + +:::caution +While both custom namespace (`as`) and `import` arguments are optional in the schema definition, due to [#1830](https://github.com/ExpediaGroup/graphql-kotlin/issues/1830) +we currently always require those values to be explicitly provided. +::: + +```graphql +directive @link(url: String!, as: String, import: [Import]) repeatable on SCHEMA +scalar Import +``` + +The `@link` directive links definitions within the document to external schemas. See [@link specification](https://specs.apollo.dev/link/v1.0) for details. + +External schemas are identified by their `url`, which ends with a name and version with the following format: `{NAME}/v{MAJOR}.{MINOR}`, +e.g. `url = "https://specs.apollo.dev/federation/v2.5"`. + +External types are associated with the target specification by annotating it with `@LinkedSpec` meta annotation. External +types defined in the specification will be automatically namespaced (prefixed with `{NAME}__`) unless they are explicitly +imported. Namespace should default to the specification name from the imported spec url. Custom namespace can be provided +by specifying `as` argument value. + +External types can be imported using the same name or can be aliased to some custom name. + +```kotlin +@LinkDirective(`as` = "custom", imports = [LinkImport(name = "@foo"), LinkImport(name = "@bar", `as` = "@myBar")], url = "https://myspecs.dev/custom/v1.0") +class MySchema +``` + +This will generate following schema: + +```graphql +schema @link(as: "custom", import : ["@foo", { name: "@bar", as: "@myBar" }], url : "https://myspecs.dev/custom/v1.0") { + query: Query +} +``` + +### `@LinkedSpec` annotation + +When importing custom specifications, we need to be able to identify whether given element is part of the referenced specification. +`@LinkedSpec` is a meta annotation that is used to indicate that given directive/type is associated with imported `@link` specification. + +In order to ensure consistent behavior, `@LinkedSpec` value have to match default specification name as it appears in the +imported url and not the aliased value. + +Example usage: + +``` +@LinkedSpec("custom") +@GraphQLDirective( + name = "foo", + locations = [DirectiveLocation.FIELD_DEFINITION] +) +annotation class Foo +``` + +In the example above, we specify that `@foo` directive is part of the `custom` specification. We can then reference `@foo` +in the `@link` specification imports + +```graphql +schema @link(as: "custom", import : ["@foo"], url : "https://myspecs.dev/custom/v1.0") { + query: Query +} + +directive @foo on FIELD_DEFINITION +``` + +If we don't import the directive, then it will automatically namespaced to the spec + +```graphql +schema @link(as: "custom", url : "https://myspecs.dev/custom/v1.0") { + query: Query +} + +directive @custom__foo on FIELD_DEFINITION +``` + +## `@override` directive + +:::note +Only available in Federation v2. +::: + +```graphql +directive @override(from: String!) on FIELD_DEFINITION +``` + +The `@override` directive is used to indicate that the current subgraph is taking responsibility for resolving the marked field away from the subgraph specified in the `from` argument, +i.e. it is used for migrating a field from one subgraph to another. Name of the subgraph to be overriden has to match the name of the subgraph that was used to publish their schema. See +[Publishing schema to Apollo Studio](https://www.apollographql.com/docs/rover/subgraphs/#publishing-a-subgraph-schema-to-apollo-studio) for additional details. + +:::caution +Only one subgraph can `@override` any given field. If multiple subgraphs attempt to `@override` the same field, a composition error occurs. +::: + +#### Example + +Given `SubgraphA` + +```graphql +type Product @key(fields: "id") { + id: String! + description: String! +} +``` + +We can override gateway `description` field resolution to resolve it in the `SubgraphB` + +```graphql +type Product @key(fields: "id") { + id: String! + name: String! + description: String! @override(from: "SubgraphA") +} +``` + +## `@policy` directive + +```graphql +directive @policy(policies: [[Policy!]!]!) on + ENUM + | FIELD_DEFINITION + | INTERFACE + | OBJECT + | SCALAR +``` + +Directive that is used to indicate that access to the target element is restricted based on authorization policies that are evaluated in a Rhai script or coprocessor. Refer to the +[Apollo Router documentation](https://www.apollographql.com/docs/router/configuration/authorization#policy) for additional details. + + +## `@provides` directive + +```graphql +# federation v1 definition +directive @provides(fields: _FieldSet!) on FIELD_DEFINITION + +# federation v2 definition +directive @provides(fields: FieldSet!) on FIELD_DEFINITION +``` + +The `@provides` directive is a router optimization hint specifying field set that can be resolved locally at the given subgraph through this particular query path. This allows you to +expose only a subset of fields from the underlying entity type to be selectable from the federated schema without the need to call other subgraphs. Provided fields specified in the +directive field set should correspond to a valid field on the underlying GraphQL interface/object type. `@provides` directive can only be used on fields returning entities. + +:::info +Federation v2 does not require `@provides` directive if field can **always** be resolved locally. `@provides` should be omitted in this situation. +::: + +#### Example 1: + +We might want to expose only name of the user that submitted a review. + +```kotlin +@KeyDirective(FieldSet("id")) +class Review(val id: String) { + @ProvidesDirective(FieldSet("name")) + fun user(): User = getUserByReviewId(id) +} + +@KeyDirective(FieldSet("userId")) +class User( + val userId: String, + @ExternalDirective val name: String +) +``` + +will generate + +```graphql +type Review @key(fields : "id") { + id: String! + user: User! @provides(fields : "name") +} + +type User @key(fields : "userId") { + userId: String! + name: String! @external +} +``` + +#### Example 2: + +Within our service, one of the queries could resolve all fields locally while other requires resolution from other subgraph + +```graphql +type Query { + remoteResolution: Foo + localOnly: Foo @provides("baz") +} + +type Foo @key("id") { + id: ID! + bar: Bar + baz: Baz @external +} +``` + +In the example above, if user selects `baz` field, it will be resolved locally from `localOnly` query but will require another subgraph invocation from `remoteResolution` query. + +## `@requires` directive + +```graphql +# federation v1 definition +directive @requires(fields: _FieldSet!) on FIELD_DEFINITON + +# federation v2 definition +directive @requires(fields: FieldSet!) on FIELD_DEFINITON +``` + +The `@requires` directive is used to specify external (provided by other subgraphs) entity fields that are needed to resolve target field. It is used to develop a query plan where +the required fields may not be needed by the client, but the service may need additional information from other subgraphs. Required fields specified in the directive field set should +correspond to a valid field on the underlying GraphQL interface/object and should be instrumented with `@external` directive. + +All the leaf fields from the specified in the `@requires` selection set have to be marked as `@external` OR any of the parent fields on the path to the leaf is marked as `@external`. + +Fields specified in the `@requires` directive will only be specified in the queries that reference those fields. This is problematic for Kotlin as the non-nullable primitive properties +have to be initialized when they are declared. Simplest workaround for this problem is to initialize the underlying property to some default value (e.g. null) that will be used if +it is not specified. This approach might become problematic though as it might be impossible to determine whether fields was initialized with the default value or the invalid/default +value was provided by the federated query. Another potential workaround is to rely on delegation to initialize the property after the object gets created. This will ensure that exception +will be thrown if queries attempt to resolve fields that reference the uninitialized property. + +#### Example + +```kotlin +@KeyDirective(FieldSet("id")) +class Product(val id: String) { + @ExternalDirective + var weight: Double by Delegates.notNull() + + @RequiresDirective(FieldSet("weight")) + fun shippingCost(): String { ... } +} +``` + +will generate + +```graphql +type Product @key(fields : "id") { + id: String! + shippingCost: String! @requires(fields : "weight") + weight: Float! @external +} +``` + +## `@requiresScopes` directive + +```graphql +directive @requiresScopes(scopes: [[Scope!]!]!) on + ENUM + | FIELD_DEFINITION + | INTERFACE + | OBJECT + | SCALAR +``` + +Directive that is used to indicate that the target element is accessible only to the authenticated supergraph users with the appropriate JWT scopes. Refer to the +[Apollo Router documentation](https://www.apollographql.com/docs/router/configuration/authorization#requiresscopes) for additional details. + +## `@shareable` directive + +:::note +Only available in Federation v2. +::: + +```graphql +directive @shareable repeatable on FIELD_DEFINITION | OBJECT +``` + +Shareable directive indicates that given object and/or field can be resolved by multiple subgraphs. If an object is marked as `@shareable` then all its fields are automatically shareable without the +need for explicitly marking them with `@shareable` directive. All fields referenced from `@key` directive are automatically shareable as well. + +:::caution +Objects/fields have to specify same shareability (i.e. `@shareable` or not) mode across ALL subgraphs. +::: + +#### Example + +```graphql +type Product @key(fields: "id") { + id: ID! # shareable because id is a key field + name: String # non-shareable + description: String @shareable # shareable +} + +type User @key(fields: "email") @shareable { + email: String # shareable because User is marked shareable + name: String # shareable because User is marked shareable +} +``` + +## `@tag` directive + +```graphql +directive @tag(name: String!) repeatable on FIELD_DEFINITION + | OBJECT + | INTERFACE + | UNION + | ARGUMENT_DEFINITION + | SCALAR + | ENUM + | ENUM_VALUE + | INPUT_OBJECT + | INPUT_FIELD_DEFINITION +``` + +Tag directive allows users to annotate fields and types with additional metadata information. Used by [Apollo Contracts](https://www.apollographql.com/docs/studio/contracts/) to expose +different graph variants to different customers. See [@tag specification](https://specs.apollo.dev/tag/v0.2/) for details. + +#### Example + +```graphql +type Product @tag(name: "MyCustomTag") { + id: String! + name: String! +} +``` + +:::caution +Apollo Contracts behave slightly differently depending on which version of Apollo Federation your graph uses (1 or 2). See [documentation](https://www.apollographql.com/docs/studio/contracts/#federation-1-limitations) +for details. +::: diff --git a/website/versioned_docs/version-7.x.x/schema-generator/federation/federated-schemas.md b/website/versioned_docs/version-7.x.x/schema-generator/federation/federated-schemas.md new file mode 100644 index 0000000000..eecfd48bd2 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/federation/federated-schemas.md @@ -0,0 +1,170 @@ +--- +id: federated-schemas +title: Federated Schemas +--- +`graphql-kotlin-federation` library extends the functionality of the `graphql-kotlin-schema-generator` and allows you to +easily generate federated GraphQL schemas directly from the code. Federated schema is generated by calling +`toFederatedSchema` function that accepts federated configuration as well as a list of regular queries, mutations and +subscriptions exposed by the schema. + +All [federated directives](federated-directives) are provided as annotations that are used to decorate your classes, +properties and functions. Since federated types might not be accessible through the regular query execution path, they +are explicitly picked up by the schema generator based on their directives. Due to the above, we also need to provide +a way to instantiate the underlying federated objects by implementing corresponding `FederatedTypeResolvers`. See +[type resolution wiki](type-resolution) for more details on how federated types are resolved. Final federated schema +is then generated by invoking the `toFederatedSchema` function +([link](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/generator/federation/toFederatedSchema.kt#L34)). + +**In order to generate valid federated schemas, you will need to annotate both your base schema and the one extending +it**. Federated Gateway (e.g. Apollo) will then combine the individual graphs to form single federated graph. + +:::caution +If you are using custom `Query` type then all of you federated GraphQL services have to use the same type. It is +not possible for federated services to have different definitions of `Query` type. +::: + +### Base Subgraph + +Base schema defines GraphQL types that will be extended by schemas exposed by other GraphQL services. In the example +below, we define base `Product` type with `id` and `description` fields. `id` is the primary key that uniquely +identifies the `Product` type object and is specified in `@key` directive. Since it is a base schema that doesn't expose +any extended functionality our FederatedTypeRegistry does not include any federated resolvers. + +```kotlin +@KeyDirective(fields = FieldSet("id")) +data class Product(val id: Int, val description: String) + +class ProductQuery { + fun product(id: Int): Product? { + // grabs product from a data source, might return null + } +} + +// Generate the schema +val hooks = FederatedSchemaGeneratorHooks(emptyList()) +val config = FederatedSchemaGeneratorConfig(supportedPackages = listOf("org.example"), hooks = hooks) +val queries = listOf(TopLevelObject(ProductQuery())) + +toFederatedSchema(config, queries) +``` + +Example above generates the following schema with additional federated types: + +```graphql +schema { + query: Query +} + +union _Entity = Product + +type Product @key(fields : "id") { + description: String! + id: Int! +} + +type Query { + _entities(representations: [_Any!]!): [_Entity]! + _service: _Service! + product(id: Int!): Product +} + +type _Service { + sdl: String! +} +``` + +### Extended Subgraph + +Extended federated GraphQL schemas provide additional functionality to the types already exposed by other GraphQL +services. In the example below, `Product` type is extended to add new `reviews` field to it. Primary key needed to +instantiate the `Product` type (i.e. `id`) has to match the `@key` definition on the base type. Since primary keys are +defined on the base type and are only referenced from the extended type, all of the fields that are part of the field +set specified in `@key` directive have to be marked as `@external`. Finally, we also need to specify an "entry point" +for the federated type - we need to create a FederatedTypeResolver that will be used to instantiate the federated +`Product` type when processing federated queries. + +```kotlin +@KeyDirective(fields = FieldSet("id")) +@ExtendsDirective +data class Product(@ExternalDirective val id: Int) { + // Add the "reviews" field to the type + suspend fun reviews(): List = getReviewByProductId(id) +} + +data class Review(val reviewId: String, val text: String) + +// Resolve a "Product" type from the _entities query +class ProductResolver : FederatedTypeSuspendResolver { + override val typeName = "Product" + + override suspend fun resolve( + environment: DataFetchingEnvironment, + representation: Map + ): Product? = + representation["id"]?.toString()?.toIntOrNull()?.let { id -> Product(id) } +} + +// Generate the schema +val resolvers = listOf(ProductResolver()) +val hooks = FederatedSchemaGeneratorHooks(resolvers) +val config = FederatedSchemaGeneratorConfig(supportedPackages = listOf("org.example"), hooks = hooks) + +toFederatedSchema(config) +``` + +Our extended schema will then be generated as: + +```graphql +schema { + query: Query +} + +union _Entity = Product + +type Product @key(fields : "id") { + id: Int! + reviews: [Review!]! +} + +type Query { + _entities(representations: [_Any!]!): [_Entity]! + _service: _Service! +} + +type Review { + reviewId: String! + text: String! +} + +type _Service { + sdl: String! +} +``` + +### Federated Supergraph + +Once we have both base and extended GraphQL services up and running, we will also need to configure Federated Gateway +to combine them into a single supergraph schema. Using the examples above, our final federated schema will be generated as: + +```graphql +schema { + query: Query +} + +type Product { + description: String! + id: Int! + reviews: [Review!]! +} + +type Review { + reviewId: String! + text: String! +} + +type Query { + product(id: String!): Product +} +``` + +See our [federation example](https://github.com/ExpediaGroup/graphql-kotlin/tree/master/examples/federation) for additional details. diff --git a/website/versioned_docs/version-7.x.x/schema-generator/federation/federation-tracing.md b/website/versioned_docs/version-7.x.x/schema-generator/federation/federation-tracing.md new file mode 100644 index 0000000000..690a932c0a --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/federation/federation-tracing.md @@ -0,0 +1,40 @@ +--- +id: federation-tracing +title: Federation Tracing +--- + +`graphql-kotlin-federation` module relies on [apollographql/federation-jvm](https://github.com/apollographql/federation-jvm) +package to provide support for Apollo Federation tracing. Tracing is turned on by including `FederatedTracingInstrumentation` +in your GraphQL instance. In order for the `FederatedTracingInstrumentation` to know whether incoming request should be +traced, we need to provide it a `apollo-federation-include-trace` header value. + +```kotlin +val schema = toFederatedSchema(myFederatedConfig, listOf(TopLevelObject(MyFederatedQuery()))) +val graphQL = GraphQL.newGraphQL(schema) + .instrumentation(FederatedTracingInstrumentation()) + .build() +``` + +### GraphQL Context Map + +:::note +Default `GraphQLContextFactory` provided by `graphql-kotlin-spring-server` populates this header information automatically. +::: + +Tracing header information can be provided by populating info directly on the GraphQL context map. + +```kotlin +val contextMap = mutableMapOf() + .also { map -> + request.headers().firstHeader(FEDERATED_TRACING_HEADER_NAME)?.let { headerValue -> + map[FEDERATED_TRACING_HEADER_NAME] = headerValue + } + } + +val executionInput = ExecutionInput.newExecutionInput() + .graphQLContext(contextMap) + .query(queryString) + .build() + +graphql.executeAsync(executionInput) +``` diff --git a/website/versioned_docs/version-7.x.x/schema-generator/federation/type-resolution.md b/website/versioned_docs/version-7.x.x/schema-generator/federation/type-resolution.md new file mode 100644 index 0000000000..347a233147 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/federation/type-resolution.md @@ -0,0 +1,130 @@ +--- +id: type-resolution +title: Federated Type Resolution +--- +In traditional (i.e. non-federated) GraphQL servers, each one of the output types is accessible through a traversal of +the GraphQL schema from a corresponding query, mutation or subscription root type. Since federated GraphQL types might +be accessed outside of the query path we need a mechanism to access them in a consistent manner. + +## `_entities` query + +A federated GraphQL server provides a custom `_entities` query that allows retrieving any of the federated extended types. +The `_entities` query accept list of "representation" objects that provide all required fields to resolve the type and +return an `_Entity` union type of all supported federated types. Representation objects are just a map of all the fields +referenced in `@key` directives as well as the target `__typename` information. If federated query type fragments also +reference fields with `@requires` and `@provides` directives, then those referenced fields should also be specified in +the target representation object. + +```graphql +query ($_representations: [_Any!]!) { + _entities(representations: $_representations) { + ... on SomeFederatedType { + fieldA + fieldB + } + } +} +``` + +:::note +`_entities` queries are automatically handled by a federated gateway and their usage is transparent for the gateway clients. +::: + +## Federated Type Resolver + +In order to simplify the integrations, `graphql-kotlin-federation` provides a default `_entities` query data fetcher or resolver that +invokes the [TypeResolver](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/generator/federation/execution/FederatedTypeResolver.kt) +that is used to resolve the specified `__typename`. + +`FederatedTypeResolver.typeName` specifies the GraphQL type name that should match the `__typename` field in the `_entities` query. + +There are two interfaces that implement the `FederatedTypeResolver`: +1. [FederatedTypeSuspendResolver](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/generator/federation/execution/FederatedTypeSuspendResolver.kt) +2. [FederatedTypePromiseResolver](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/generator/federation/execution/FederatedTypePromiseResolver.kt) + +### Federated Type Suspend Resolver + +`FederatedTypeSuspendResolver.resolve` receives a representation of the target `__typename` and will execute +the suspending function on a `CoroutineScope` to **asynchronously wait** to complete the target entity or `NULL` if entity cannot be resolved. + +`FederatedTypeSuspendResolver.resolve` will be invoked based on how many representations of the target entity were +requested in the `_entities` query. + +```kotlin +// This service does not own the "Product" type but is extending it with new fields +@KeyDirective(fields = FieldSet("id")) +@ExtendsDirective +class Product(@ExternalDirective val id: String) { + fun newField(): String = getNewFieldByProductId(id) +} + +// This is how the "Product" class is created from the "_entities" query using suspending resolver +class ProductResolver : FederatedTypeSuspendResolver { + override val typeName: String = "Product" + + override suspend fun resolve( + environment: DataFetchingEnvironment, + representation: Map + ): Product? { + val id = representation["id"]?.toString() + // Instantiate product using id, otherwise return null + return if (id != null) { + Product(id) + } else { + null + } + } +} +``` + +:::note +this suspend implementation relies on the same coroutine scope propagation as the +default `FunctionDataFetcher`. See [asynchronous models documentation](../execution/async-models.md) for additional details. +Additionally you can also use `FederatedTypePromiseResolver` which is compatible with `DataLoader`'s async model given that returns +a `CompletableFuture`, that way you get advantage of batching and deduplication of transactions to downstream. +::: + +### Federated Type Promise Resolver + +`FederatedTypePromiseResolver.resolve` receives a representation of the target `__typename` and provides a `CompletableFuture` of +a nullable instance of target entity. + +```kotlin +// This service does not own the "Product" type but is extending it with new fields +@KeyDirective(fields = FieldSet("id")) +@ExtendsDirective +class Product(@ExternalDirective val id: String) { + fun newField(): String = getNewFieldByProductId(id) +} + +// This is how the "Product" class is created from the "_entities" query using promise resolver +class ProductResolver : FederatedTypePromiseResolver { + override val typeName: String = "Product" + + override fun resolve( + environment: DataFetchingEnvironment, + representation: Map + ): CompletableFuture { + val id = representation["id"]?.toString() + // use dataloader to resolve Product by id + return environment.getDataLoader("ProductDataLoader").load(id) + } +} +``` + +## Provide FederatedTypeResolvers to FederatedSchema + +Provide a `List` to the `FederatedSchemaGeneratorHooks` and `graphql-kotlin` will create the +data fetcher or resolver using your custom federated type resolvers + +```kotlin +val resolvers = listOf(productResolver) +val hooks = FederatedSchemaGeneratorHooks(resolvers) +val config = FederatedSchemaGeneratorConfig(supportedPackages = listOf("org.example"), hooks = hooks) +val schema = toFederatedSchema(config) +``` + +:::note +If you are using `graphql-kotlin-spring-server`, each of your FederatedTypeResolvers can be marked as Spring Beans +and will automatically be added to the `FederatedSchemaGeneratorHooks` by using autoconfiguration. +::: diff --git a/website/versioned_docs/version-7.x.x/schema-generator/schema-generator-getting-started.mdx b/website/versioned_docs/version-7.x.x/schema-generator/schema-generator-getting-started.mdx new file mode 100644 index 0000000000..d9d06e0f40 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/schema-generator-getting-started.mdx @@ -0,0 +1,144 @@ +--- +id: schema-generator-getting-started +title: Getting Started +--- + + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Install + +Using a JVM dependency manager, link `graphql-kotlin-schema-generator` to your project. + + + + + +```kotlin +implementation("com.expediagroup", "graphql-kotlin-schema-generator", latestVersion) +``` + + + + +```xml + + com.expediagroup + graphql-kotlin-schema-generator + ${latestVersion} + +``` + + + + +## Usage + +`graphql-kotlin-schema-generator` provides a single function, `toSchema`, to generate a schema from Kotlin objects. + +```kotlin +data class Widget(val id: Int, val value: String) + +class WidgetQuery { + fun widgetById(id: Int): Widget? { + // grabs widget from a data source + } +} + +class WidgetMutation { + fun saveWidget(value: String): Widget { + // some logic for saving widget + } +} + +val widgetQuery = WidgetQuery() +val widgetMutation = WidgetMutation() +val schema = toSchema( + config = yourCustomConfig(), + queries = listOf(TopLevelObject(widgetQuery)), + mutations = listOf(TopLevelObject(widgetMutation)) +) +``` + +will generate: + +```graphql +schema { + query: Query + mutation: Mutation +} + +type Query { + widgetById(id: Int!): Widget +} + +type Mutation { + saveWidget(value: String!): Widget! +} + +type Widget { + id: Int! + value: String! +} +``` + +Any `public` functions defined on a query, mutation, or subscription Kotlin class will be translated into GraphQL fields on the object +type. `toSchema` will then recursively apply Kotlin reflection on the specified classes to generate all +remaining object types, their properties, functions, and function arguments. + +The generated `GraphQLSchema` can then be used to expose a GraphQL API endpoint. + +## `toSchema` + +This function accepts five arguments: `config`, `queries`, `mutations`, `subscriptions` and a `schemaObject`. The `queries`, `mutations` +and `subscriptions` are a list of `TopLevelObject`s and will be used to generate corresponding GraphQL root types. `schemaObject` is an +optional `TopLevelObject` reference to the annotated schema object. See below on why we use this wrapper class. The `config` contains all +the extra information you need to pass, including custom hooks, supported packages, and name overrides. See the [Generator Configuration](./customizing-schemas/generator-config.md) +documentation for more information. + +You can see the definition for `toSchema` [in the +source](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/toSchema.kt). + +## `TopLevelObject` + +`toSchema` uses Kotlin reflection to build a GraphQL schema from given classes using `graphql-java`'s schema builder. We +don't just pass a `KClass` though, we have to actually pass an object, because the functions on the object are +transformed into the data fetchers. In most cases, a `TopLevelObject` can be constructed with just an object: + +```kotlin +class Query { + fun getNumber() = 1 +} + +val topLevelObject = TopLevelObject(Query()) + +toSchema(config = config, queries = listOf(topLevelObject)) +``` + +In the above case, `toSchema` will use `topLevelObject::class` as the reflection target, and `Query` as the data fetcher +target. + + +### Dynamic `TopLevelObject` +In a lot of cases, such as with Spring AOP, the object (or bean) being used to generate a schema is a dynamic proxy. In +this case, `topLevelObject::class` is not `Query`, but rather a generated class that will confuse the schema generator. +To specify the `KClass` to use for reflection on a proxy, pass the class to `TopLevelObject`: + +```kotlin +@Component +class Query { + fun getNumber() = 1 +} + +val query = getObjectFromBean() +val customDef = TopLevelObject(query, Query::class) + +toSchema(config, listOf(customDef)) +``` diff --git a/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/arguments.md b/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/arguments.md new file mode 100644 index 0000000000..175eb5f744 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/arguments.md @@ -0,0 +1,109 @@ +--- +id: arguments +title: Arguments +--- +Method arguments are automatically exposed as part of the arguments to the corresponding GraphQL fields. + +```kotlin +class Query { + fun doSomething(value: Int): Boolean = true +} +``` + +The above Kotlin code will generate following GraphQL schema: + +```graphql +type Query { + doSomething(value: Int!): Boolean! +} +``` + +This behavior is true for all arguments except for the special classes for the [GraphQLContext](../execution/contextual-data) and the [DataFetchingEnvironment](../execution/data-fetching-environment) + +## Input Types + +Query, Mutation, and Subscription function arguments are automatically converted to GraphQL input fields. GraphQL makes a +distinction between input and output types and requires unique names for all the types. Since we can use the same +objects for input and output in our Kotlin functions, `graphql-kotlin-schema-generator` will automatically append +an `Input` suffix to the GraphQL name of input objects. + +For example, the following code: + +```kotlin +class WidgetMutation { + fun processWidget(widget: Widget): Widget { + if (widget.value == null) { + widget.value = 42 + } + return widget + } +} + +data class Widget(var value: Int? = null) { + fun multiplyValueBy(multiplier: Int): Int? = value?.times(multiplier) +} +``` + +Will generate the following schema: + +```graphql +type Mutation { + processWidget(widget: WidgetInput!): Widget! +} + +type Widget { + value: Int + multiplyValueBy(multiplier: Int!): Int +} + +input WidgetInput { + value: Int +} +``` + +Note that only fields are exposed in the input objects. Functions will only be available on the GraphQL output types. + +:::caution +All input object fields have to be exposed through a public primary constructor. This primary constructor is used to instantiate +the input objects at runtime when resolving the queries. +::: + +If you know a type will only be used for input types you can call your class something like `CustomTypeInput`. The library will not +append `Input` if the class name already ends with `Input` but that means you can not use this type as output because +the schema would have two types with the same name and that would be invalid. + +If you would like to restrict an Kotlin class to only being used as input or output, see how to use [GraphQLValidObjectLocations](../customizing-schemas/restricting-input-output.md) + +## Optional fields + +Kotlin requires variables/values to be initialized upon their declaration either from the user input OR by providing +defaults (even if they are marked as nullable). + +Therefore, in order for a GraphQL input field to be optional, **it needs to be nullable and must have a default value**. + +```kotlin +fun doSomethingWithOptionalInput(requiredValue: Int, optionalValue: Int? = null): String { + return "requiredValue=$requiredValue, optionalValue=$optionalValue" +} +``` + +## Default values + +Default Kotlin values are supported, however the default value information is not available to the schema due to the [reflection limitations of Kotlin](https://github.com/ExpediaGroup/graphql-kotlin/issues/53). +The parameters must also be defined as optional (nullable) in the schema, as the only way a default value will be used is when the client does not specify any value in the request. + +```kotlin +fun print(message: String? = "hello"): String? = message +``` + +The following operations will return the message in the comments + +```graphql +query PrintMessages { + first: print(message = "foo") # foo + second: print(message = null) # null + third: print # hello +} +``` + +If you need logic to determine when a client passed in a value vs when the default value was used (aka the argument was missing in the request), see [optional undefined arguments](../execution/optional-undefined-arguments.md). diff --git a/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/enums.md b/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/enums.md new file mode 100644 index 0000000000..ebebf04c3f --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/enums.md @@ -0,0 +1,76 @@ +--- +id: enums +title: Enums +--- +Enums are automatically mapped to GraphQL enum type. + +```kotlin +enum class MyEnumType { + ONE, + TWO +} +``` + +Above enum will be generated as following GraphQL object + +```graphql +enum MyEnumType { + ONE + TWO +} +``` + +### Converting a Java enum to a GraphQL Enum + +If you want to use Java enums from another package, but you **don't** want +include everything from that package using [`supportedPackages`][config] or you want +to customize the GraphQL type, you can use [schema generator hooks][config] to +associate the Java enum with a runtime [`GraphQLEnumType`][javadoc]. + +[config]: ../customizing-schemas/generator-config.md + +[javadoc]: https://javadoc.io/doc/com.graphql-java/graphql-java/latest/index.html + +Step 1: Create a GraphQLEnumType using the Java enum values + +```java +// in some other package +public enum Status { + APPROVED, + DECLINED +} +``` + +```kotlin +val statusEnumType = GraphQLEnumType.newEnum() + .name("Status") + .values(Status.values().map { + GraphQLEnumValueDefinition.newEnumValueDefinition() + .value(it.name) + .build() + }) + .build() +``` + +Step 2: Add a schema generation hook + +```kotlin +class CustomSchemaGeneratorHooks : SchemaGeneratorHooks { + + override fun willGenerateGraphQLType(type: KType): GraphQLType? { + return when (type.classifier as? KClass<*>) { + Status::class.java -> statusEnumType + else -> super.willGenerateGraphQLType(type) + } + } +} +``` + +Step 3. Use your Java enum anywhere in your schema + +```kotlin +@Component +class StatusQuery : Query { + fun currentStatus: Status = getCurrentStatus() +} +``` diff --git a/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/fields.md b/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/fields.md new file mode 100644 index 0000000000..20787bb3d4 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/fields.md @@ -0,0 +1,24 @@ +--- +id: fields +title: Types and Fields +--- +`graphql-kotlin-schema-generator` uses [reflection](https://kotlinlang.org/docs/reflection.html) to automatically map +Kotlin classes and enums to the corresponding GraphQL types. + +By default, all public properties and functions with a [valid GraphQL name](https://spec.graphql.org/draft/#sec-Names) +and a supported return type will be mapped to a corresponding GraphQL field. Kotlin return types have to be either one of the +[supported scalars](./scalars.md) or a custom Kotlin type defined within supported packages. Nullability information is +automatically inferred from the underlying Kotlin return type. + +Additional built-in validations +* function types aka lambdas property types are currently not supported by the schema generator +* automatically generated data class methods (`componentN`, `copy`, `equals`, `hashCode`, `toString`) are filtered out + +Default behavior can be customized. Fields can be [renamed](../customizing-schemas/renaming-fields.md) or [excluded](../customizing-schemas/excluding-fields.md). +Support for additional types or validations can be added by providing an instance of custom [SchemaGeneratorHook](../customizing-schemas/generator-config.md#schemageneratorhooks). + +## Type Inheritance + +`graphql-kotlin-schema-generator` provides support for both GraphQL [unions](./unions.md) and [interfaces](./interfaces.md). +Superclasses and interfaces can be excluded from the schema by marking them with `@GraphQLIgnore` annotation or by providing +custom filtering logic in a custom [SchemaGeneratorHook](../customizing-schemas/generator-config.md#schemageneratorhooks). diff --git a/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/interfaces.md b/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/interfaces.md new file mode 100644 index 0000000000..38cf079f5f --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/interfaces.md @@ -0,0 +1,129 @@ +--- +id: interfaces +title: Interfaces +--- +Kotlin interfaces, abstract and sealed classes will be mapped to a GraphQL interface. Due to the GraphQL distinction between interface +and a [union type](./unions.md), Kotlin interfaces need to specify at least one common field (property or a function). Superclasses and +interfaces can be excluded from the schema by marking them with `@GraphQLIgnore` annotation or by providing custom filtering logic in a +custom schema generator hook. + +:::note +[The GraphQL spec](http://spec.graphql.org/June2018/#sec-Interfaces) does not allow interfaces to be used as input. +This means that while it is valid Kotlin code to have an interface as an argument, upon schema generation, an exception will be thrown. +::: + +```kotlin +interface Animal { + val type: AnimalType + fun sound(): String +} + +enum class AnimalType { + CAT, + DOG +} + +class Dog : Animal { + override val type = AnimalType.DOG + + override fun sound() = "bark" + + fun barkAtEveryone(): String = "bark at everyone" +} + +class Cat : Animal { + override val type = AnimalType.CAT + + override fun sound() = "meow" + + fun ignoreEveryone(): String = "ignore everyone" +} + +class PolymorphicQuery { + + fun animal(type: AnimalType): Animal? = when (type) { + AnimalType.CAT -> Cat() + AnimalType.DOG -> Dog() + else -> null + } +} +``` + +The above code will produce the following GraphQL schema: + +```graphql +interface Animal { + type: AnimalType! + sound: String! +} + +enum AnimalType { + CAT + DOG +} + +type Cat implements Animal { + type: AnimalType! + ignoreEveryone: String! + sound: String! +} + +type Dog implements Animal { + type: AnimalType! + barkAtEveryone: String! + sound: String! +} + +type TopLevelQuery { + animal(type: AnimalType!): Animal +} +``` + +## Abstract and Sealed Classes + +[Abstract](https://kotlinlang.org/docs/reference/classes.html#abstract-classes) and [sealed](https://kotlinlang.org/docs/reference/sealed-classes.html) classes can also be used for GraphQL interface types. + +```kotlin +abstract class Shape(val area: Double) +class Circle(radius: Double) : Shape(PI * radius * radius) +class Square(sideLength: Double) : Shape(sideLength * sideLength) + +sealed class Pet(val name: String) { + class Dog(name: String, val goodBoysReceived: Int) : Pet(name) + class Cat(name: String, val livesRemaining: Int) : Pet(name) +} +``` + +## Nested Interfaces + +Interfaces can implement other interfaces. + +```kotlin +interface Foo { + val foo: String +} + +interface Bar : Foo { + val bar: String +} + +class Baz(override val foo: String, override val bar: String) : Bar +``` + +Code above generates following schema + +```graphql +interface Foo { + foo: String! +} + +interface Bar implements Foo { + bar: String! + foo: String! +} + +type Baz implements Bar & Foo { + bar: String! + foo: String! +} +``` diff --git a/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/lists.md b/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/lists.md new file mode 100644 index 0000000000..108fbb4491 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/lists.md @@ -0,0 +1,45 @@ +--- +id: lists +title: Lists +--- +`kotlin.collections.List` is automatically mapped to the GraphQL `List` type. Type arguments provided to Kotlin collections +are used as the type arguments in the GraphQL `List` type. + +```kotlin +class SimpleQuery { + fun generateList(): List { + // some logic here that generates list + } + + fun doSomethingWithIntList(ints: List): String { + // some logic here that processes list + } +} +``` + +The above Kotlin class would produce the following GraphQL schema: + +```graphql +type Query { + generateList: [String!]! + doSomethingWithIntList(ints: [Int!]!): String! +} +``` + +## Arrays and Unsupported Collection Types + +Currently, the GraphQL spec only supports `Lists`. Therefore, even though Java and Kotlin support number of other collection +types, `graphql-kotlin-schema-generator` only explicitly supports `Lists`. Other collection types such as `Sets` (see [#201](https://github.com/ExpediaGroup/graphql-kotlin/issues/201)) +and arbitrary `Map` data structures are not supported out of the box. While we do not recommend using `Map` or `Set` in the schema, +they could be supported with the use of the schema hooks. + +Due to the [argument deserialization issues](https://github.com/ExpediaGroup/graphql-kotlin/pull/1379), arrays are currently not supported + +```kotlin +override fun willResolveMonad(type: KType): KType = when (type.classifier) { + Set::class -> List::class.createType(type.arguments) + else -> type +} +``` + +See [Discussion #1110](https://github.com/ExpediaGroup/graphql-kotlin/discussions/1110) for more details. diff --git a/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/nested-arguments.md b/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/nested-arguments.md new file mode 100644 index 0000000000..19de6db8a7 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/nested-arguments.md @@ -0,0 +1,76 @@ +--- +id: nested-arguments +title: Nested Resolvers and Shared Arguments +--- +There are a few ways in which shared arguments can be accessed from different resolver levels. Say we have the following schema: + +```graphql +type Query { + findUser(id: String!): User +} + +type User { + photos(numberOfPhotos: Int!): [Photo!]! +} + +type Photo { + url: String! +} +``` + +In Kotlin code, when we are resolving `photos`, if we want access to the parent field `findUser` and its arguments there +are a couple ways we can access it, + +## DataFetchingEnvironment + +You can add the `DataFetchingEnvironment` as an argument. This class will be ignored by the schema generator and will allow +you to view the entire query sent to the server. See more in the [DataFetchingEnvironment documentation](../execution/data-fetching-environment.md) + +```kotlin +class User { + fun photos(environment: DataFetchingEnvironment, numberOfPhotos: Int): List { + val username = environment.executionStepInfo.parent.arguments["id"] + return getPhotosFromDataSource(username, numberOfPhotos) + } +} +``` + +## GraphQL Context Object (Deprecated) + +:::danger +Support for custom GraphQL context object is deprecated and will be removed in future releases. Please migrate to use +generic GraphQL context map. +::: + +You can add the `GraphQLContext` as an argument. This class will be ignored by the schema generator and will allow you to +view the context object you set up in the data fetchers. See more in the [GraphQLContext documentation](../execution/contextual-data.md) + +```kotlin +class User { + fun photos(context: MyContextObject, numberOfPhotos: Int): List { + val userId = context.getDataFromMyCustomFunction() + return getPhotosFromDataSource(userId, numberOfPhotos) + } +} +``` + +## Excluding Arguments from the Schema + +You can construct the child objects by passing down arguments as non-public fields or annotate the argument with [@GraphQLIgnore](../customizing-schemas/excluding-fields.md) + +```kotlin +class User(private val userId: String) { + + fun photosProperty(numberOfPhotos: Int): List { + return getPhotosFromDataSource(userId, numberOfPhotos) + } + + fun photosIgnore(@GraphQLIgnore userId: String, numberOfPhotos: Int): List { + return getPhotosFromDataSource(userId, numberOfPhotos) + } +} +``` + +## Spring Integration + +See [Writing Schemas with Spring](../../server/spring-server/spring-schema.md) for integration details. diff --git a/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/nullability.md b/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/nullability.md new file mode 100644 index 0000000000..fe8575f27c --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/nullability.md @@ -0,0 +1,28 @@ +--- +id: nullability +title: Nullability +--- +Both GraphQL and Kotlin have a concept of `nullable` as a marked typed. As a result we can automatically generate null +safe schemas from Kotlin code. + +```kotlin +class SimpleQuery { + + fun generateNullableNumber(): Int? { + val num = Random().nextInt(100) + return if (num < 50) num else null + } + + fun generateNumber(): Int = Random().nextInt(100) +} +``` + +The above Kotlin code would produce the following GraphQL schema: + +```graphql +type Query { + generateNullableNumber: Int + + generateNumber: Int! +} +``` diff --git a/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/scalars.md b/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/scalars.md new file mode 100644 index 0000000000..e2d6986207 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/scalars.md @@ -0,0 +1,269 @@ +--- +id: scalars +title: Scalars +--- +## Primitive Types + +`graphql-kotlin-schema-generator` can directly map most Kotlin "primitive" types to standard GraphQL scalar types or +extended scalar types provided by `graphql-java`. + +| Kotlin Type | GraphQL Type | +|-------------------| ------------ | +| `kotlin.String` | `String` | +| `kotlin.Boolean` | `Boolean` | +| `kotlin.Int` | `Int` | +| `kotlin.Double` | `Float` | +| `kotlin.Float` | `Float` | + +:::note +The GraphQL spec uses the term `Float` for signed double‐precision fractional values. `graphql-java` maps this to a `java.lang.Double` for the execution. The generator will map both `kotlin.Double` and `kotlin.Float` to GraphQL `Float` but we recommend you use `kotlin.Double`. +::: + +## GraphQL ID + +GraphQL supports the scalar type `ID`, a unique identifier that is not intended to be human-readable. IDs are +serialized as a `String`. To expose a GraphQL `ID` field, you must use the `com.expediagroup.graphql.generator.scalars.ID` +class, which is an *inline value class* that wraps the underlying `String` value. + +:::note +`graphql-java` supports additional types (`String`, `Int`, `Long`, or `UUID`) but [due to serialization issues](https://github.com/ExpediaGroup/graphql-kotlin/issues/317) we can only directly support Strings. +::: + +Since `ID` is a value class, it may be represented at runtime as a wrapper or directly as underlying type. Due to the generic +nature of the query processing logic we *always* end up with up a wrapper type when resolving the field value. As a result, +in order to ensure that underlying scalar value is correctly serialized, we need to explicitly unwrap it by registering +`IDValueUnboxer` with your GraphQL instance. + +```kotlin +// registering custom value unboxer +val graphQL = GraphQL.newGraphQL(graphQLSchema) + .valueUnboxer(IDValueUnboxer()) + .build() +``` + +:::note +`IDValueUnboxer` bean is automatically configured by `graphql-kotlin-spring-server`. +::: + +```kotlin +data class Person( + val id: ID, + val name: String +) + +fun findPersonById(id: ID) = Person(id, "John Smith") + +fun generateRandomId(): ID = ID(UUID.randomUUID().toString()) +``` + +This would produce the following schema: + +```graphql +schema { + query: Query +} + +type Query { + findPersonById(id: ID!): Person! + generateRandomId: ID! +} + +type Person { + id: ID! + name: String! +} +``` + +## Custom Scalars + +By default, `graphql-kotlin-schema-generator` uses Kotlin reflections to generate all schema objects. If you want to +apply custom behavior to the objects, you can also define your own custom scalars. Custom scalars have to be explicitly +added to the schema through `SchemaGeneratorHooks.willGenerateGraphQLType`. +See the [Generator Configuration](../customizing-schemas/generator-config.md) documentation for more information. + +Example usage + +```kotlin +class CustomSchemaGeneratorHooks : SchemaGeneratorHooks { + + override fun willGenerateGraphQLType(type: KType): GraphQLType? = when (type.classifier as? KClass<*>) { + UUID::class -> graphqlUUIDType + else -> null + } +} + +val graphqlUUIDType = GraphQLScalarType.newScalar() + .name("UUID") + .description("A type representing a formatted java.util.UUID") + .coercing(UUIDCoercing) + .build() + +object UUIDCoercing : Coercing { + override fun parseValue(input: Any, graphQLContext: GraphQLContext, locale: Locale): UUID = runCatching { + UUID.fromString(serialize(input, graphQLContext, locale)) + }.getOrElse { + throw CoercingParseValueException("Expected valid UUID but was $input") + } + + override fun parseLiteral(input: Value<*>, variables: CoercedVariables, graphQLContext: GraphQLContext, locale: Locale): UUID { + val uuidString = (input as? StringValue)?.value + return runCatching { + UUID.fromString(uuidString) + }.getOrElse { + throw CoercingParseLiteralException("Expected valid UUID literal but was $uuidString") + } + } + + override fun serialize(dataFetcherResult: Any, graphQLContext: GraphQLContext, locale: Locale): String = runCatching { + dataFetcherResult.toString() + }.getOrElse { + throw CoercingSerializeException("Data fetcher result $dataFetcherResult cannot be serialized to a String") + } +} +``` + +Once the scalars are registered you can use them anywhere in the schema as regular objects. + +### Inline Value Classes + +It is often beneficial to create a wrapper around the underlying primitive type to better represent its meaning. Inline value classes can be used +to optimize such use cases - Kotlin compiler will attempt to use underlying type directly whenever possible and only keep the wrapper classes +whenever it is necessary. + +:::note +Nullable value class types may result in a runtime `IllegalArgumentException` due to https://youtrack.jetbrains.com/issue/KT-31141. This should be resolved in Kotlin 1.7.0+. +::: + +#### Representing Unwrapped Value Classes in the Schema as the Underlying Type + +In order to represent unwrapped inline value classes in your schema as the underlying type, you need to register it using hooks and also provide value unboxer that will be used by +`graphql-java` when dealing with its wrapper object. + +```kotlin +@JvmInline +value class MyValueClass( + val value: String +) + +class MyQuery : Query { + fun inlineValueClassQuery(value: MyValueClass? = null): MyValueClass = value ?: MyValueClass("default") +} + +class MySchemaGeneratorHooks : SchemaGeneratorHooks { + override fun willGenerateGraphQLType(type: KType): GraphQLType? = when (type.classifier) { + MyValueClass::class -> Scalars.GraphQLString + else -> null + } +} + +class MyValueUnboxer : IDValueUnboxer() { + override fun unbox(value: Any?): Any? = when (value) { + is MyValueClass -> `object`.value + else -> super.unbox(`object`) + } +} + +val config = SchemaGeneratorConfig( + supportedPackages = listOf("com.example"), + hooks = MySchemaGeneratorHooks() +) +val schema = toSchema( + config = config, + queries = listOf(TopLevelObject(MyQuery())) +) +val graphQL = GraphQL.newGraphQL(graphQLSchema) + .valueUnboxer(MyValueUnboxer()) + .build() +``` + +This will generate a schema that exposes value classes as the corresponding wrapped type: + +```graphql +type Query { + inlineValueClassQuery(value: String): String! +} +``` + +:::note +GraphQL ID scalar type is represented using inline value class. When registering additional inline value classes you should extend the `IDValueUnboxer` to ensure IDs will be correctly processed. Alternatively, extend `DefaultValueUnboxer` and handle the `ID` value class as above. + +If you are using `graphql-kotlin-spring-server` you should create an instance of your bean as + +```kotlin +@Bean +fun idValueUnboxer(): IDValueUnboxer = MyValueUnboxer() +``` +::: + +#### Representing Unwrapped Value Classes in the Schema as a Custom Scalar Type + +In many cases, it may be useful to represent value classes in the schema as a custom scalar type, as the additional type information is often useful for clients. In this form, the value class is unwrapped, but uses a custom scalar type to preserve the extra type information. + +To do this, define a coercer for the value class that transforms it to and from the underlying type, and register it with the custom schema hooks: + +```kotlin +val graphqlMyValueClassType: GraphQLScalarType = GraphQLScalarType.newScalar() + .name("MyValueClass") + .description( + """ + |Represents my value class as a String value. + |""".trimMargin() + ) + .coercing(MyValueClassCoercing) + .build() + +object MyValueClassCoercing : Coercing { + override fun parseValue(input: Any, graphQLContext: GraphQLContext, locale: Locale): MyValueClass = ... + override fun parseLiteral(input: Value<*>, variables: CoercedVariables, graphQLContext: GraphQLContext, locale: Locale): MyValueClass = ... + override fun serialize(dataFetcherResult: Any, graphQLContext: GraphQLContext, locale: Locale): String = ... +} + +class CustomSchemaGeneratorHooks : SchemaGeneratorHooks { + override fun willGenerateGraphQLType(type: KType): GraphQLType? = when (type.classifier as? KClass<*>) { + MyValueClass::class -> graphqlMyValueClassType + else -> null + } +} +``` + +This will generate the schema that exposes value classes as a scalar type: + +```graphql +scalar MyValueClass + +type Query { + inlineValueClassQuery(value: MyValueClass): MyValueClass! +} +``` + +#### Representing Value Classes in the Schema as Objects + +To do this, simply use the value class directly without defining any coercers or unboxers as in the previous sections. + +This will generate the schema that exposes value classes as a wrapped type, similar to a regular class: + +```graphql +input MyValueClassInput { + value: String! +} + +type MyValueClass { + value: String! +} + +type Query { + inlineValueClassQuery(value: MyValueClassInput): MyValueClass! +} +``` + +## Common Issues + +### Extended Scalars + +By default, `graphql-kotlin` only supports the primitive scalar types listed above. If you are looking to use common java types as scalars, you need to include the [graphql-java-extended-scalars](https://github.com/graphql-java/graphql-java-extended-scalars) library and set up the hooks (see above), or write the logic yourself for how to resolve these custom scalars. + +The most popular types that require extra configuration are: `LocalDate`, `DateTime`, `Instant`, `ZonedDateTime`, `URL`, `UUID` + +### `TypeNotSupportedException` + +If you see the following message `Cannot convert ** since it is not a valid GraphQL type or outside the supported packages ***`. This means that you need to update the [generator configuration](../customizing-schemas/generator-config.md) to include the package of your type or you did not properly set up the hooks to register the new type. diff --git a/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/schema.md b/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/schema.md new file mode 100644 index 0000000000..494edf1f28 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/schema.md @@ -0,0 +1,53 @@ +--- +id: schema +title: Schema +--- +## Schema Object + +`SchemaGenerator` automatically generates schema object from the provided list of `TopLevelObjects` representing `queries`, `mutations` and `subscriptions`. + +In order to provide [schema description](../customizing-schemas/documenting-schema.md) or to specify [schema directives](../customizing-schemas/directives.md), we need to provide `TopLevelObject` reference to a schema class. + +:::caution +Only annotations are processed on the schema object. Generator will throw an exception if schema class contains any properties or functions. +::: + +In the example below, we provide custom description and apply `@contact` directive on the schema object. + +```kotlin +@ContactDirective( + name = "My Team Name", + url = "https://myteam.slack.com/archives/teams-chat-room-url", + description = "send urgent issues to [#oncall](https://yourteam.slack.com/archives/oncall)." +) +@GraphQLDescription("My schema description") +class MySchema + +class HelloWorldQuery { + fun helloWorld() = "Hello World!" +} + +// generate schema +val schema = toSchema( + config = yourCustomConfig(), + queries = listOf(TopLevelObject(HelloWorldQuery())), + schemaObject = TopLevelObject(MySchema()) +) +``` + +Will generate + +```graphql +schema @contact(description : "send urgent issues to [#oncall](https://yourteam.slack.com/archives/oncall).", name : "My Team Name", url : "https://myteam.slack.com/archives/teams-chat-room-url"){ + query: Query +} + +type Query { + helloWorld: String! +} +``` + +:::note +`graphql-java` currently does not include schema description in the generated SDL (it is available in the introspection results only). +Fixed in https://github.com/graphql-java/graphql-java/pull/2856. +::: diff --git a/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/unions.md b/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/unions.md new file mode 100644 index 0000000000..e562c1da7c --- /dev/null +++ b/website/versioned_docs/version-7.x.x/schema-generator/writing-schemas/unions.md @@ -0,0 +1,139 @@ +--- +id: unions +title: Unions +--- + +GraphQL Kotlin allows for two ways of defining unions in the schema + +## Marker Interfaces + +Marker interfaces (i.e. interfaces without any common fields or methods) are exposed as GraphQL union types. All the +types that implement the marker interface, and are available on the classpath, will be automatically exposed as +objects in the schema. + +:::note +[The GraphQL spec](http://spec.graphql.org/June2018/#sec-Unions) does not allow unions to be used as input. +This means that while it is valid Kotlin code to have a marker inteface as an argument, upon schema generation, an exception will be thrown. +::: + +```kotlin +interface BodyPart + +class LeftHand(val field: String): BodyPart + +class RightHand(val property: Int): BodyPart + +class PolymorphicQuery { + fun whichHand(whichHand: String): BodyPart = when (whichHand) { + "right" -> RightHand(12) + else -> LeftHand("hello world") + } +} +``` + +The above will generate following GraphQL schema + +```graphql +union BodyPart = LeftHand | RightHand + +type LeftHand { + field: String! +} + +type RightHand { + property: Int! +} + +type Query { + whichHand(whichHand: String!): BodyPart! +} +``` + +## `@GraphQLUnion` +:::note +Instead of this custom annotation, the [@GraphQLType](../customizing-schemas/custom-type-reference.md) annotation may be a better option +::: + +The downside to marker interface unions is that you can not edit classes included in dependencies to implement new schema unions. +For example in an SDL-First world you could have this Kotlin class defined in some library. + +```kotlin +class SharedModel(val foo: String) +``` + +And then write your schema as the following + + +```graphql +# From library +type SharedModel { + foo: String! +} + +# Defined in our schema +type ServiceModel { + bar: String! +} + +# Defined in our schema +union CustomUnion = SharedModel | ServiceModel + +type Query { + getModel: CustomUnion +} +``` + +But this is not currently possible in the full code-generation approach. Instead, you will need to use the `@GraphQLUnion` annotation on your functions or properties. + +### Example Usage +```kotlin +// Defined in some other library +class SharedModel(val foo: String) + +// Our code +class ServiceModel(val bar: String) + +class Query { + @GraphQLUnion( + name = "CustomUnion", + possibleTypes = [SharedModel::class, ServiceModel::class], + description = "Return one or the other model" + ) + fun getModel(): Any = ServiceModel("abc") +} +``` + +If directives are needed, this can also be used as a meta-annotation + +### Example Usage +```kotlin +// Defined in some other library +class SharedModel(val foo: String) + +// Our code +class ServiceModel(val bar: String) + + +@SomeDirective +@GraphQLUnion( + name = "CustomUnion", + possibleTypes = [SharedModel::class, ServiceModel::class], + description = "Return one or the other model" +) +annotation class CustomUnion + +class Query { + @CustomUnion + fun getModel(): Any = ServiceModel("abc") +} +``` + +The annotation requires the `name` of the new union to create and the `possibleTypes` that this union can return. +However since we can not enforce the type checks anymore, you must use `Any` as the return type. + +### Limitations +Even when using it as a meta-annotation, it is not always possible to add directives to the union definition +if the directive annotation cannot apply to an annotation class. +You will have to modify the type with [schema generator hooks](../customizing-schemas/generator-config.md). + +[@GraphQLType](../customizing-schemas/custom-type-reference.md) annotation can be used as a workaround to this issue. diff --git a/website/versioned_docs/version-7.x.x/server/automatic-persisted-queries/automatic-persisted-queries.md b/website/versioned_docs/version-7.x.x/server/automatic-persisted-queries/automatic-persisted-queries.md new file mode 100644 index 0000000000..8050ddab50 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/automatic-persisted-queries/automatic-persisted-queries.md @@ -0,0 +1,147 @@ +--- +id: automatic-persisted-queries +title: Automatic Persisted Queries (APQ) +--- + +[APQ is technique created by Apollo](https://www.apollographql.com/docs/apollo-server/performance/apq/) to improve +GraphQL network performance with zero build-time configuration by sending smaller [GraphQL HTTP requests](https://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md). +A smaller request payload reduces bandwidth utilization and speeds up GraphQL Client loading times. + +A persisted query is a parsed and validated query document that is cached on a GraphQL Server, along with a unique identifier (SHA-256 hash). +This way clients can send this identifier instead of the corresponding query which will drastically reduce the request size. + +To persist a query, a GraphQL Server must first receive it from a Client, then, subsequent requests can just include the identifier +instead of the query. + +```mermaid +sequenceDiagram; + Client->>GraphQL Kotlin Server: Sends SHA-256 hash of query to execute + Note over GraphQL Kotlin Server: Fails to find persisted query + GraphQL Kotlin Server->>Client: Responds with error + Client->>GraphQL Kotlin Server: Sends both query AND SHA-256 hash + Note over GraphQL Kotlin Server: Persists query and SHA-256 hash + GraphQL Kotlin Server->>Client: Executes query and returns result + Note over Client: Time passes + Client->>GraphQL Kotlin Server: Sends SHA-256 hash of query to execute + Note over GraphQL Kotlin Server: Finds persisted query previously parsed and validated + GraphQL Kotlin Server->>Client: Executes query and returns result + Note over Client: Client can opt-out from sending SHA-256 hash + Client->>GraphQL Kotlin Server: Sends query without SHA-256 + Note over GraphQL Kotlin Server: Still persist parsed and validated query + GraphQL Kotlin Server->>Client: Executes query and returns result + Client->>GraphQL Kotlin Server: Sends query without SHA-256 + Note over GraphQL Kotlin Server: Finds parsed and validated query +``` + +## AutomaticPersistedQueriesProvider + +To support APQ we have created `AutomaticPersistedQueriesProvider` which is an implementation of +the [graphql-java PreparsedDocumentProvider](https://github.com/graphql-java/graphql-java/blob/master/src/main/java/graphql/execution/preparsed/PreparsedDocumentProvider.java), +which is the interface that allows caching for parsed and validated GraphQL Documents (AST). + +`AutomaticPersistedQueriesProvider` requires the implementation of `AutomaticPersistedQueriesCache` as a constructor argument. +`AutomaticPersistedQueriesCache` is an interface that specifies the contract of how to retrieve documents. + +**Note:** `graphql-kotlin-automatic-persisted-queries` provides a default in-memory cache implementation of `AutomaticPersistedQueriesCache` +called `DefaultAutomaticPersistedQueriesCache`. In order to take full advantage of Automatic Persisted Queries, it's recommended +to use an external cache mechanism like Redis. + +### Usage in GraphQL Kotlin Server + +Provide an instance of `AutomaticPersistedQueryProvider` in the GraphQL engine builder `preparsedDocumentProvider` method: + +```kotlin +val schema = "your schema" +val runtimeWiring = RuntimeWiring.newRuntimeWiring().build() // your runtime wiring +val automaticPersistedQueryProvider = AutomaticPersistedQueriesProvider(DefaultAutomaticPersistedQueriesCache()) + +val graphQL = GraphQL + .newGraphQL(SchemaGenerator().makeExecutableSchema(SchemaParser().parse(schema), runtimeWiring)) + .preparsedDocumentProvider(automaticPersistedQueryProvider) + .build() +``` + +:::info +`graphql-kotlin-spring-server` provides convenient integration of Automatic Persisted Queries functionality through simple configuration. +Automatic Persisted Queries can be enabled by configuring following properties: +```yaml +graphql: + automaticPersistedQueries: + enabled: true +``` +::: + +If you want to implement a different cache mechanism using Caffeine or REDIS you can just simply provide a Spring Bean and the +autoconfigured `AutomaticPersistedQueryProvider` will use your custom implementation of the cache. + +```kotlin +class REDISAutomaticPersistedQueriesCache : AutomaticPersistedQueriesCache { + override fun getOrElse(key: String, supplier: () -> PreparsedDocumentEntry): CompletableFuture { + // your implementation + } +} + +@Configuration +class ApplicationConfiguration { + @Bean + fun redisAutomaticPersistedQueriesCache(): PreparsedDocumentProvider = REDISAutomaticPersistedQueriesCache() +} +``` +### Usage in Clients + +Clients that want to use APQ will need to calculate the unique identifier (SHA-256 hash) of a query and send it +in the extension section of a [GraphQL HTTP request](https://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md#json-encoding) + +Example Payload: + +```json +{ + "variables": { + "foo": "bar" + }, + "extensions": { + "persistedQuery": { + "version": 1, + "sha256Hash": "ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38" + } + } +} +``` + +As seen, in an APQ request, the query field of the request payload is optional. + +### Errors + +All errors are going to be provided in the `errors` array in the JSON Response: + +1. `PersistedQueryNotFound` if `query` was not provided and preparsed document could not be found in the cache using the provided `sha256Hash` +the GraphQL Error response will be: +```json +{ + "errors": [ + { + "message": "PersistedQueryNotFound", + "extensions": { + "persistedQueryId": "ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38", + "classification": "PersistedQueryNotFound" + } + } + ] +} +``` + +2. `PersistedQueryIdInvalid` if `query` was provided but the provided `sha256Hash` does not match with the `query` +the GraphQL Error response will be: +```json +{ + "errors": [ + { + "message": "PersistedQueryIdInvalid", + "extensions": { + "persistedQueryId": "ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38", + "classification": "PersistedQueryIdInvalid" + } + } + ] +} +``` diff --git a/website/versioned_docs/version-7.x.x/server/data-loader/data-loader-instrumentation.mdx b/website/versioned_docs/version-7.x.x/server/data-loader/data-loader-instrumentation.mdx new file mode 100644 index 0000000000..0aca14ec53 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/data-loader/data-loader-instrumentation.mdx @@ -0,0 +1,316 @@ +--- +id: data-loader-instrumentation +title: Data Loader Instrumentations +--- + + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +`graphql-kotlin-dataloader-instrumentation` is set of custom [Instrumentations](https://www.graphql-java.com/documentation/instrumentation/) +that will calculate the right moment to dispatch `KotlinDataLoader`s across single or batch GraphQL operations. + +These custom instrumentations follow the similar approach as the default [DataLoaderDispatcherInstrumentation](https://github.com/graphql-java/graphql-java/blob/master/src/main/java/graphql/execution/instrumentation/dataloader/DataLoaderDispatcherInstrumentation.java) +from `graphql-java`, the main difference is that regular instrumentations apply to a single `ExecutionInput` aka [GraphQL Operation](https://www.graphql-java.com/documentation/execution#queries), +whereas these custom instrumentations apply to multiple GraphQL operations (say a BatchRequest) and stores their state in the `GraphQLContext` +allowing batching and deduplication of transactions across those multiple GraphQL operations. + +By default, each GraphQL operation is processed independently of each other. Multiple operations can be processed +together as if they were single GraphQL request if they are part of the same batch request. + +The `graphql-kotlin-dataloader-instrumentation` module contains 2 custom `DataLoader` instrumentations. + +## Dispatching by level + +The `DataLoaderLevelDispatchedInstrumentation` tracks the state of all `ExecutionInputs` across operations. When a certain +field dispatches, it will check if all fields across all operations for a particular level were dispatched and if the condition is met, +it will dispatch all the data loaders. + +### Example + +You can find additional examples in our [unit tests](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/executions/graphql-kotlin-dataloader-instrumentation/src/test/kotlin/com/expediagroup/graphql/dataloader/instrumentation/level/DataLoaderLevelDispatchedInstrumentationTest.kt). + + + + + +```graphql +query Q1 { + astronaut(id: 1) { # async + id + name + missions { # async + id + designation + } + } +} + +query Q2 { + astronaut(id: 2) { # async + id + name + missions { # async + id + designation + } + } +} +``` + + + + +![Image of data loader level dispatched instrumentation](../../assets/data-loader-level-dispatched-instrumentation.png) + +* The `astronaut` `DataFetcher` uses a `AstronautDataLoader` which will be dispatched when **Level 1** of those 2 operations +is dispatched, causing the `AstronautDataLoader` to load 2 astronauts. +* The `missions` `DataFetcher` uses a `MissionsByAstronautDataLoader` which will be dispatched when **Level 2** of those 2 operations +is dispatched, causing the `MissionsByAstronautDataLoader` to load 2 lists of missions by astronaut. + + + + +### Usage + +In order to enable batching by level, you need to configure your GraphQL instance with the `DataLoaderLevelDispatchedInstrumentation`. + +```kotlin +val graphQL = GraphQL.Builder() + .doNotAddDefaultInstrumentations() + .instrumentation(DataLoaderLevelDispatchedInstrumentation()) + // configure schema, type wiring, etc. + .build() +``` + +This data loader instrumentation relies on a global state object that needs be stored in the GraphQLContext map + +```kotlin +val graphQLContext = mapOf( + ExecutionLevelDispatchedState::class to ExecutionLevelDispatchedState(queries.size) +) +``` + +:::info +`graphql-kotlin-spring-server` provides convenient integration of batch loader functionality through simple configuration. +Batching by level can be enabled by configuring following properties: +```yaml +graphql: + batching: + enabled: true + strategy: LEVEL_DISPATCHED +``` +::: + +### Limitations + +This instrumentation is a good option if your **GraphQLServer** will receive a batched request with operations of the same type, +in those cases batching by level is enough, however, this solution is far from being the most optimal as we don't necessarily want to dispatch by level. + +## Dispatching by synchronous execution exhaustion + +The most optimal time to dispatch all data loaders is when all possible synchronous execution paths across all batch +operations were exhausted. Synchronous execution path is considered exhausted (or completed) when all currently processed +data fetchers were either resolved to a scalar or a future promise. + +Let's analyze how GraphQL execution works, but first lets check some GraphQL concepts: + +**DataFetcher** + +Each field in GraphQL has a resolver aka `DataFetcher` associated with it, some fields will use specialized `DataFetcher`s +that knows how to go to a database or make a network request to get field information while most simply take +data from the returned memory objects. + + +**Execution Strategy** + +The process of finding values for a list of fields from the GraphQL Query, using a recursive strategy. + +### Example + +You can find additional examples in our [unit tests](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/executions/graphql-kotlin-dataloader-instrumentation/src/test/kotlin/com/expediagroup/graphql/dataloader/instrumentation/syncexhaustion/DataLoaderSyncExecutionExhaustedInstrumentationTest.kt). + + + + +```graphql +query Q1 { + astronaut(id: 1) { # async + id + name + missions { # async + id + designation + } + } +} + +query Q2 { + nasa { #sync + astronaut(id: 2) { # async + id + name + missions { # async + id + designation + } + } + address { # sync + street + zipCode + } + phoneNumber + } +} +``` + + + +![Image of data loader level dispatched instrumentation](../../assets/data-loader-level-sync-execution-exhausted-instrumentation.png) + +**The order of execution of the queries will be:** + +***for Q1*** +1. Start an `ExecutionStrategy` for the `root` field of the query, to concurrently resolve `astronaut` field. + * `astronaut` **DataFetcher** will invoke the `AstronautDataLoader` and will return a `CompletableFuture` so we can consider this path exhausted. + +***for Q2*** +1. Start an `ExecutionStrategy` for the `root` field of the query, to concurrently resolve `nasa` field. + * `nasa` **DataFetcher** will synchronously return a `Nasa` object, so we can descend more that path. +2. Start an `ExecutionStrategy` for the `nasa` field of the `root` field of the query to concurrently resolve `astronaut`, `address` and `phoneNumber`. + * `astronaut` **DataFetcher** will invoke the `AstronautDataLoader` and will return a `CompletableFuture` so we can consider this path exhausted + * `address` **DataFetcher** will synchronously return an `Address` object, so we can descend more that path. + * `phoneNumber` **DataFetcher** will return a scalar, so we can consider this path exhausted. +3. Start an `ExecutionStrategy` for the `address` field of the `nasa` field to concurrently resolve `street` and `zipCode`. + * `street` **DataFetcher** will return a scalar, so we can consider this path exhausted. + * `zipCode` **DataFetcher** will return a scalar, so we can consider this path exhausted. + +**At this point we can consider the synchronous execution exhausted and the `AstronautDataLoader` has 2 keys to be dispatched, +if we proceed dispatching all data loaders the execution will continue as following:** + +***for Q1*** +1. Start and `ExecutionStrategy` for the `astronaut` field of the `root` field of the query to concurrently resolve `id`, `name` and `mission` fields. + * `id` **DataFetcher** will return a scalar, so we can consider this path exhausted. + * `name` **DataFetcher** will return a scalar, so we can consider this path exhausted. + * `missions` **DataFetcher** will invoke the `MissionsByAstronautDataLoader` and will return a `CompletableFuture>` so we can consider this path exhausted. + +***for Q2*** +1. Start and `ExecutionStrategy` for the `astronaut` field of the `nasa` field of the query to concurrently resolve `id`, `name` and `mission` fields. + * `id` **DataFetcher** will return a scalar, so we can consider this path exhausted. + * `name` **DataFetcher** will return a scalar, so we can consider this path exhausted. + * `missions` **DataFetcher** will invoke the `MissionsByAstronautDataLoader` and will return a `CompletableFuture>` so we can consider this path exhausted. + +**At this point we can consider the synchronous execution exhausted and the `MissionsByAstronautDataLoader` has 2 keys to be dispatched, +if we proceed dispatching all data loaders the execution will continue to just resolve scalar fields.** + + + + +### Usage + +In order to enable batching by synchronous execution exhaustion, you need to configure your GraphQL instance with the `DataLoaderSyncExecutionExhaustedInstrumentation`. + +```kotlin +val graphQL = GraphQL.Builder() + .doNotAddDefaultInstrumentations() + .instrumentation(DataLoaderSyncExecutionExhaustedInstrumentation()) + // configure schema, type wiring, etc. + .build() +``` + +This data loader instrumentation relies on a global state object that needs be stored in the GraphQLContext map + +```kotlin +val graphQLContext = mapOf( + SyncExecutionExhaustedState::class to SyncExecutionExhaustedState( + queries.size, + kotlinDataLoaderRegistry + ) +) +``` + +:::info +`graphql-kotlin-spring-server` provides convenient integration of batch loader functionality through simple configuration. +Batching by synchronous execution exhaustion can be enabled by configuring following properties: +```yaml +graphql: + batching: + enabled: true + strategy: SYNC_EXHAUSTION +``` +::: + +## Multiple data loaders per field data fetcher + +There are some cases when a GraphQL Schema doesn't match the data source schema, a field can require data from multiple +sources to be fetched and you will still want to do batching with data loaders. + +### DispatchIfNeeded + +`graphql-kotlin-dataloader-instrumentation` includes a helpful extension function of the `CompletableFuture` class +so that you can easily instruct the [previously selected data loader instrumentation](./data-loader-instrumentation#dispatching-by-level) +that you want to apply batching and deduplication to a chained `DataLoader` in your `DataFetcher` (resolver). + +### Example + +```graphql +type Query { + astronaut(id: ID!): Astronaut +} + +# In the data source, let's say a database, +# an `Astronaut` can have multiple `Mission`s and a `Mission` can have multiple `Planet`s. +type Astronaut { + id: ID! + name: String! + # The schema exposes the `Astronaut` `Planet`s, without traversing his `Mission`s. + planets: [Planet!]! +} + +type Planet { + id: ID! + name: String! +} +``` +The `Astronaut` `planets` data fetcher (resolver) will contain the logic to chain two data loaders, +first collect missions by astronaut, and then, planets by mission. + +**DataLoaders** + +For this specific example we would need 2 `DataLoader`s + +1. **MissionsByAstronaut:** to retrieve `Mission`s by a given `Astronaut`. +2. **PlanetsByMission:** to retrieve `Planet`s by a given `Mission`. + +**Fetching logic** +```kotlin +class Astronaut { + fun getPlanets( + astronautId: Int, + environment: DataFetchingEnvironment + ): CompletableFuture> { + val missionsByAstronautDataLoader = environment.getDataLoader("MissionsByAstronautDataLoader") + val planetsByMissionDataLoader = environment.getDataLoader("PlanetsByMissionDataLoader") + return missionsByAstronautDataLoader + .load(astronautId) + // chain data loader + .thenCompose { missions -> + planetsByMissionDataLoader + .loadMany(missions.map { mission -> mission.id }) + // extension function to schedule a dispatch of registry if needed + .dispatchIfNeeded(environment) + } +} +``` diff --git a/website/versioned_docs/version-7.x.x/server/data-loader/data-loader.md b/website/versioned_docs/version-7.x.x/server/data-loader/data-loader.md new file mode 100644 index 0000000000..d155d24f4f --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/data-loader/data-loader.md @@ -0,0 +1,210 @@ +--- +id: data-loader +title: Data Loaders +--- +Data Loaders are a popular caching pattern from the [JavaScript GraphQL implementation](https://github.com/graphql/dataloader). +`graphql-java` provides [support for this pattern](https://www.graphql-java.com/documentation/v16/batching/) +using the `DataLoader` and `DataLoaderRegistry`. + +Since `graphql-kotlin` allows you to abstract the schema generation and data fetching code, you may not even need +data loaders if instead you have some persistant cache on your server. + +```kotlin +class User(val id: ID) { + // The friendService and userService, which have nothing to do with GraphQL, + // should be concerned with caching and batch calls instead of your schema classes + fun getFriends(): List { + val friends: List = friendService.getFriends(id) + return userService.getUsers(friends) + } + +} +``` + +If you still want to use data loaders though, they are supported through the common interfaces. + +`graphql-kotlin-dataloader` module provides convenient abstractions over the [java-dataloader](https://github.com/graphql-java/java-dataloader). + +## `KotlinDataLoader` + +To help in the registration of `DataLoaders`, we have created an interface `KotlinDataLoader`: + +```kotlin +interface KotlinDataLoader { + val dataLoaderName: String + fun getDataLoader(graphQLContext: GraphQLContext): DataLoader +} +``` + +This allows for library users to still have full control over the creation of the `DataLoader` and its various configuration +options but also allows common server code to handle the registration, generation and execution of the request. + +Additionally, the `getDataLoader` method provides access to the `graphQLContext` that was created from the [GraphQLContextFactory](../graphql-context-factory.md), +allowing you to use the `graphQLContext` as [context of the DataLoader](https://www.graphql-java.com/documentation/batching/#passing-context-to-your-data-loader). + +## `KotlinDataLoaderRegistryFactory` + +The [GraphQLRequestHandler](../graphql-request-handler.md) accepts an optional `KotlinDataLoaderRegistryFactory`. +which generates a new `KotlinDataLoaderRegistry` on every request. The registry is a map of a unique data loader names to a `DataLoader` object that handles the cache for an output type in your graph. +A `DataLoader` caches the types by some unique value, usually by the type id, and can handle different types of batch requests. + +```kotlin +class UserDataLoader : KotlinDataLoader { + override val dataLoaderName = "UserDataLoader" + override fun getDataLoader(graphQLContext: GraphQLContext) = + DataLoaderFactory.newDataLoader { ids -> + CompletableFuture.supplyAsync { + ids.map { id -> userService.getUser(id) } + } + } +} + +class FriendsDataLoader : KotlinDataLoader> { + override val dataLoaderName = "FriendsDataLoader" + override fun getDataLoader(graphQLContext: GraphQLContext) = + DataLoaderFactory.newDataLoader( + { ids, batchLoaderEnvironment -> + val context = batchLoaderEnvironment.getContext() + // do something with graphQLContext + CompletableFuture.supplyAsync { + ids.map { id -> + val friends: List = friendService.getFriends(id) + userService.getUsers(friends) + } + } + }, + DataLoaderOptions.newOptions() + .setCachingEnabled(false) + .setBatchLoaderContextProvider { graphQLContext } + ) +} + +val dataLoaderRegistryFactory = KotlinDataLoaderRegistryFactory( + UserDataLoader(), FriendsDataLoader() +) + +val dataLoaderRegistry = dataLoaderRegistryFactory.generate() +``` + +## `KotlinDataLoaderRegistry` + +[KotlinDataLoaderRegistry](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/executions/graphql-kotlin-dataloader/src/main/kotlin/com/expediagroup/graphql/dataloader/KotlinDataLoaderRegistry.kt) +is a decorator of the original `graphql-java` [DataLoaderRegistry](https://github.com/graphql-java/java-dataloader/blob/master/src/main/java/org/dataloader/DataLoaderRegistry.java) +that keeps track of all underlying `DataLoader`s futures. By keeping track of to cache map containing returned futures, +we get more granular control when to dispatch data loader calls. + +## `getValueFromDataLoader` + +`graphql-kotlin-server` includes a helpful extension function on the `DataFetchingEnvironment` so that you can easily retrieve values from the data loaders in your schema code. + +```kotlin +class User(val id: ID) { + @GraphQLDescription("Get the users friends using data loader") + fun getFriends(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture> { + return dataFetchingEnvironment.getValueFromDataLoader("FriendsDataLoader", id) + } +} +``` + +## DataLoaders and Coroutines + +`graphql-java` relies on `CompletableFuture`s for scheduling and asynchronously executing GraphQL operations. +While we can provide native support for coroutines for data fetchers (aka field resolvers) because they are resolved +independently, we cannot easily provide native support for the `DataLoader` pattern as it relies +on `CompletableFuture` state machine internals and we cannot update it to use coroutines without fully rewriting +GraphQL Java execution engine. + +If you would like to use `DataLoader` pattern in your project, you have to update your data fetchers (aka field resolvers) to return +`CompletableFuture` from the invoked `DataLoader`. + +### Example + +Consider the following query: + +```graphql +fragment UserFragment on User { + id + name +} +query GetUsersFriends { + user_1: user(id: 1) { + ...UserFragment + } + user_2: user(id: 2) { + ...UserFragment + } +} +``` + +And the corresponding code that will autogenerate schema: + +```kotlin +class MyQuery( + private val userService: UserService +) : Query { + suspend fun getUser(id: Int): User = userService.getUser(id) +} + +class UserService { + suspend fun getUser(id: Int): User = // async logic to get user + suspend fun getUsers(ids: List): List = // async logic to get users +} +``` + +When we execute the above query, we will end up calling `UserService#getUser` twice which will result in two independent +downstream service/database calls. This problem is called N+1 problem. By using `DataLoader` pattern, +we can solve this problem and only make a single downstream request/query. + +Lets create the `UserDataLoader`: + +```kotlin +class UserDataLoader : KotlinDataLoader { + override val dataLoaderName = "UserDataLoader" // 1 + override fun getDataLoader(graphQLContext: GraphQLContext) = // 2 + DataLoaderFactory.newDataLoader( + { ids, batchLoaderEnvironment -> + val coroutineScope = // 3 + batchLoaderEnvironment.getContext()?.get() + ?: CoroutineScope(EmptyCoroutineContext) // 4 + + coroutineScope.future { // 5 + userService.getUsers(ids) + } + }, + DataLoaderOptions.newOptions() + .setBatchLoaderContextProvider { graphQLContext } + ) +} + +``` + +There are some things going on here: + +1. We define the `UserDataLoader` with name "UserDataLoader". +2. The `KotlinDataLoader#getDataLoader(GraphQLContext)` method returns a `DataLoader`, which `BatchLoader` function should return a `List` and `BatchLoaderEnvironment` context is the `GraphQLContext`. +3. Given that we **don't want** to change our `UserService` async model that is using coroutines, we need a `CoroutineScope`, [which is conveniently available](../../schema-generator/execution/async-models/#coroutines) in the `GraphQLContext` and accessible through the `BatchLoaderEnvironment`. +4. After retrieving the `CoroutineScope` from the `batchLoaderEnvironment` we will be able to execute the `userService.getUsers(ids)` suspendable function. +5. We interoperate the suspendable function result to a `CompletableFuture` using [coroutineScope.future](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.future/future.html). + +Finally, we need to update `user` field resolver, to return the `CompletableFuture` from the invoked `DataLoader`. +Make sure to update method signature to also accept the `dataFetchingEnvironment` as you need to pass it to `DataLoader#load` method to be able to execute the request in appropriate coroutine scope. + +```kotlin +class MyQuery( + private val userService: UserService +) : Query { + fun getUser(id: Int, dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture = + dataFetchingEnvironment + .getDataLoader("UserDataLoader") + .load(id, dataFetchingEnvironment) +} + +class UserService { + suspend fun getUser(id: Int): User { + // logic to get user + } + suspend fun getUsers(ids: List): List { + // logic to get users, this method is called from the DataLoader + } +} +``` diff --git a/website/versioned_docs/version-7.x.x/server/graphql-context-factory.md b/website/versioned_docs/version-7.x.x/server/graphql-context-factory.md new file mode 100644 index 0000000000..283c936bd1 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/graphql-context-factory.md @@ -0,0 +1,66 @@ +--- +id: graphql-context-factory +title: GraphQLContextFactory +--- + +:::note +If you are using `graphql-kotlin-spring-server`, see the [Spring specific documentation](./spring-server/spring-graphql-context.md). +::: + +`GraphQLContextFactory` provides a generic mechanism for generating a GraphQL context for each request. + +```kotlin +interface GraphQLContextFactory { + suspend fun generateContext(request: Request): GraphQLContext = + emptyMap().toGraphQLContext() +} +``` + +Given the generic server request, the interface should attempt to create a `GraphQLContext` to be used for every new operation. +interface from `graphql-kotlin-schema-generator`. See [execution context](../schema-generator/execution/contextual-data.md) +for more info on how the context can be used in the schema functions. + +## Coroutine Context + +By default, `graphql-kotlin-server` creates a supervisor scope with currently available coroutine context. You can provide +additional context elements using `GraphQLContextFactory` by populating `CoroutineContext::class` entry in the context map +or by implementing `graphQLCoroutineContext()` (deprecated) on a custom context object. + +```kotlin +@Component +class MyCustomContextFactory : GraphQLContextFactory() { + override suspend fun generateContext(request: ServerRequest): GraphQLContext = + mapOf( + CoroutineContext::class to MDCContext() + ).toGraphQLContext() +} +``` + +`GraphQLServer` will then attempt to create supervisor coroutine scope by combining current coroutine context with custom +coroutine context provided by the `GraphQLContextFactory`. This scope will then be used by `FunctionDataFetcher` to execute +all suspendable functions. + +## Suspendable Factory +The interface is marked as a `suspend` function to allow the asynchronous fetching of context data. +This may be helpful if you need to call some other services to calculate a context value. + +## Server-Specific Abstractions + +A specific `graphql-kotlin-*-server` library may provide an abstract class on top of this interface so users only have to +be concerned with the context class and not the server class type. +For example the `graphql-kotlin-spring-server` provides the following class, which sets the request type: + +```kotlin +abstract class SpringGraphQLContextFactory : GraphQLContextFactory +``` + +## HTTP Headers and Cookies + +For common use cases around authorization, authentication, or tracing you may need to read HTTP headers and cookies. +This should be done in the `GraphQLContextFactory` and relevant data should be added to the context to be accessible during schema execution. + +## Federated Tracing + +See [federation tracing support](../schema-generator/federation/federation-tracing.md) documentation for details. + +The reference server implementation `graphql-kotlin-spring-server` [supports federated tracing in the context](./spring-server/spring-graphql-context.md). diff --git a/website/versioned_docs/version-7.x.x/server/graphql-request-handler.md b/website/versioned_docs/version-7.x.x/server/graphql-request-handler.md new file mode 100644 index 0000000000..c914f70bea --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/graphql-request-handler.md @@ -0,0 +1,13 @@ +--- +id: graphql-request-handler +title: GraphQLRequestHandler +--- +The `GraphQLRequestHandler` is an open and extendable class that contains the basic logic to get a `GraphQLResponse`. + +It requires a `GraphQLSchema` and a [KotlinDataLoaderRegistryFactory](./data-loader/data-loader.md) in the constructor. +For each request, it accepts a `GraphQLRequest` and an optional [GraphQLContext](graphql-context-factory.md), +and calls the `KotlinDataLoaderRegistryFactory` to generate a new `KotlinDataLoaderRegistry`. Then all of these objects are sent to the schema for +execution and the result is mapped to a `GraphQLResponse`. + +There shouldn't be much need to change this class but if you wanted to add custom logic +or logging it is possible to override it or just create your own. diff --git a/website/versioned_docs/version-7.x.x/server/graphql-request-parser.md b/website/versioned_docs/version-7.x.x/server/graphql-request-parser.md new file mode 100644 index 0000000000..fd12e5aaa1 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/graphql-request-parser.md @@ -0,0 +1,39 @@ +--- +id: graphql-request-parser +title: GraphQLRequestParser +--- +The `GraphQLRequestParser` interface is required to parse the library-specific HTTP request object into the common `GraphQLServerRequest` class. + +```kotlin +interface GraphQLRequestParser { + suspend fun parseRequest(request: Request): GraphQLServerRequest? +} +``` + +While not officially part of the spec, there is a standard format used by most GraphQL clients and servers for [serving GraphQL over HTTP](https://graphql.org/learn/serving-over-http/). +Following the above convention, GraphQL clients should generally use HTTP POST requests with the following body structure + +```json +{ + "query": "...", + "operationName": "...", + "variables": { "myVariable": "someValue" } +} +``` + +where + +- `query` is a required field and contains the operation (query, mutation, or subscription) to be executed +- `operationName` is an optional string, only required if multiple operations are specified in the `query` string. +- `variables` is an optional map of JSON objects that are referenced as input arguments in the `query` string + +GraphQL Kotlin server supports both single and batch GraphQL requests. Batch requests are represented as a list of individual +GraphQL requests. When processing batch requests, the same context will be used for processing all requests and the server will +respond with a list of GraphQL responses. + +If the request is not a valid GraphQL format, the interface should return `null` and let the server specific code return a bad request status to the client. +This is not the same as a GraphQL error or an exception thrown by the schema. +Those types of errors should still parse the request and return a valid response with errors set via the [GraphQLRequestHandler](./graphql-request-handler.md). + +This interface should only be concerned with parsing the request, not about forwarding info to the context or execution. +That is handled by the [GraphQLContextFactory](./graphql-context-factory.md). diff --git a/website/versioned_docs/version-7.x.x/server/graphql-server.md b/website/versioned_docs/version-7.x.x/server/graphql-server.md new file mode 100644 index 0000000000..9a51638c97 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/graphql-server.md @@ -0,0 +1,35 @@ +--- +id: graphql-server +title: GraphQLServer +--- +`graphql-kotlin-server` provides common code and basic interfaces to setup a GraphQL server in any framework. + +The official reference implementations are: + +- [graphql-kotlin-spring-server](./spring-server/spring-overview.mdx) + +We recommend using one of the implementations as the common code has very little logic but you can still use the common +package to create implementation for other libraries (Ktor, Spark, etc). + +There are demos of how to use these server libraries in the `/examples` folder of the repo. + +## `GraphQLServer` + +The top level object in the common package is `GraphQLServer`. +This class is open for extensions and requires that you specify the type of the http requests you will be handling. + +- For [Spring Reactive](https://spring.io/reactive) we would define a `GraphQLServer` +- For [Ktor](https://ktor.io/) we would define a `GraphQLServer` + +In its simplest form, a GraphQL server has the following responsibilties: + +- Parse the GraphQL request info from the HTTP request +- Create a `GraphQLContext` object from the HTTP request to be used during execution +- Send the request and the context to the GraphQL schema to execute and get a response (may contain `data` or `errors`) +- Send the reponse back to the client over HTTP + +Most of the logic in a GraphQL server that is specific to your application is already in the schema, so if we have interfaces for all these +common functions, we can abstract away the library specific features. + +The one method we don't have an interface for is sending back the response to the client. Once you get the response back from `GraphQLServer`, +we leave the rest up to your application to call it's server specific methods to encode and send the response. diff --git a/website/versioned_docs/version-7.x.x/server/ktor-server/ktor-configuration.md b/website/versioned_docs/version-7.x.x/server/ktor-server/ktor-configuration.md new file mode 100644 index 0000000000..275ebf5bb4 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/ktor-server/ktor-configuration.md @@ -0,0 +1,201 @@ +--- +id: ktor-configuration +title: Ktor Plugin Configuration +--- + +`graphql-kotlin-ktor-server` plugin can be configured by using DSL when installing the plugin. Configuration is broken into multiple +groups related to specific functionality. See sections below for details. + +```kotlin +install(GraphQL) { + schema { + // configuration that controls schema generation logic + } + engine { + // configurations that control GraphQL execution engine + } + server { + // configurations that control GraphQL HTTP server + } +} +``` + +## Configuration Files + +Ktor supports specifying configurations in `application.conf` (HOCON) or `application.yaml` file. By default, only HOCON format +is supported. To use a YAML configuration file, you need to add the `ktor-server-config-yaml` dependency to your project dependencies. +See [Ktor documentation](https://ktor.io/docs/configuration-file.html) for details. + +:::caution +Not all configuration properties can be specified in your configuration file. You will need to use DSL to configure more advanced features +that cannot be represented in the property file syntax (e.g. any instantiated objects). +::: + +All configuration options in `application.conf` format, with their default values are provided below. + +```kotlin +graphql { + schema { + // this is a required property that you need to set to appropriate value + // example value is just provided for illustration purposes + packages = [ + "com.example" + ] + federation { + enabled = false + tracing { + enabled = true + debug = false + } + } + } + engine { + automaticPersistedQueries { + enabled = false + } + batching { + enabled = false + strategy = LEVEL_DISPATCHED + } + introspection { + enabled = true + } + } +} +``` + +## Schema Configuration + +This section configures `graphql-kotlin-schema-generation` logic and is the **only** section that has to be configured. +At a minimum you need to configure the list of packages that can contain your GraphQL schema definitions and a list of queries. + +All configuration options, with their default values are provided below. + +```kotlin +schema { + // this is a required property that you need to set to appropriate value + // example value is just provided for illustration purposes + packages = listOf("com.example") + // non-federated schemas, require at least a single query + queries = listOf() + mutations = listOf() + subscriptions = listOf() + schemaObject = null + // federated schemas require federated hooks + hooks = NoopSchemaGeneratorHooks + topLevelNames = TopLevelNames() + federation { + enabled = false + tracing { + enabled = true + debug = false + } + } + // required for GraalVM native servers + typeHierarchy = null +} +``` + +## GraphQL Execution Engine Configuration + +This section configures `graphql-java` execution engine that will be used to process your GraphQL requests. + +All configuration options, with their default values are provided below. + +```kotlin +engine { + automaticPersistedQueries { + enabled = false + } + // DO NOT enable default batching logic if specifying custom provider + batching { + enabled = false + strategy = SYNC_EXHAUSTION + } + introspection { + enabled = true + } + dataFetcherFactoryProvider = SimpleKotlinDataFetcherFactoryProvider() + dataLoaderRegistryFactory = KotlinDataLoaderRegistryFactory() + exceptionHandler = SimpleDataFetcherExceptionHandler() + executionIdProvider = null + idValueUnboxer = IDValueUnboxer() + instrumentations = emptyList() + // DO NOT specify custom provider if enabling default batching logic + preparsedDocumentProvider = null +} +``` + +## Server Configuration + +This section configures your GraphQL HTTP server. + +All configuration options, with their default values are provided below. + +```kotlin +server { + contextFactory = DefaultKtorGraphQLContextFactory() + jacksonConfiguration = { } + requestParser = KtorGraphQLRequestParser(jacksonObjectMapper().apply(jacksonConfiguration)) +} +``` + +## Routes Configuration + +GraphQL Kotlin Ktor Plugin DOES NOT automatically configure any routes. You need to explicitly configure `Routing` +plugin with GraphQL routes. This allows you to selectively enable routes and wrap them in some additional logic (e.g. `Authentication`). + +GraphQL Kotlin Ktor Plugin provides following `Route` extensions that can be called when configuring `Routing` plugin. + +### GraphQL POST route + +This is the main route for processing your GraphQL requests. By default, it will use `/graphql` endpoint and respond +using chunked encoding. + +```kotlin +fun Route.graphQLPostRoute(endpoint: String = "graphql", streamingResponse: Boolean = true, jacksonConfiguration: ObjectMapper.() -> Unit = {}): Route +``` + +### GraphQL GET route + +:::caution +Only `Query` operations are supported by the GET route. +::: + +GraphQL route for processing GET requests. By default, it will use `/graphql` endpoint and respond using chunked encoding. + +```kotlin +fun Route.graphQLGetRoute(endpoint: String = "graphql", streamingResponse: Boolean = true, jacksonConfiguration: ObjectMapper.() -> Unit = {}): Route +``` + +### GraphQL Subscriptions route + +GraphQL route for processing subscriptions. By default, it will use `/subscriptions` endpoint and handle +requests using [graphql-transport-ws](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md) protocol handler. + +```kotlin +fun Route.graphQLSubscriptionsRoute( + endpoint: String = "subscriptions", + protocol: String? = null, + handlerOverride: KtorGraphQLSubscriptionHandler? = null, +) +``` + +See related [Subscriptions](./ktor-subscriptions.md) document for more info. + +### GraphQL SDL route + +Convenience route to expose endpoint that returns your GraphQL schema in SDL format. + +```kotlin +fun Route.graphQLSDLRoute(endpoint: String = "sdl"): Route +``` + +### GraphiQL IDE route + +[GraphiQL IDE](https://github.com/graphql/graphiql) is a convenient tool that helps you to easily interact +with your GraphQL server. + +```kotlin +fun Route.graphiQLRoute(endpoint: String = "graphiql", graphQLEndpoint: String = "graphql"): Route +``` diff --git a/website/versioned_docs/version-7.x.x/server/ktor-server/ktor-graphql-context.md b/website/versioned_docs/version-7.x.x/server/ktor-server/ktor-graphql-context.md new file mode 100644 index 0000000000..d4772d0f3d --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/ktor-server/ktor-graphql-context.md @@ -0,0 +1,48 @@ +--- +id: ktor-graphql-context +title: Generating GraphQL Context +--- + +`graphql-kotlin-ktor-server` provides a Ktor specific implementation of [GraphQLContextFactory](../graphql-context-factory.md) +and the context. + +* `KtorGraphQLContextFactory` - Generates GraphQL context map with federated tracing information per request + +If you are using `graphql-kotlin-ktor-server`, you should extend `DefaultKtorGraphQLContextFactory` to automatically +support federated tracing. + +```kotlin +class CustomGraphQLContextFactory : DefaultKtorGraphQLContextFactory() { + override suspend fun generateContext(request: ApplicationRequest): GraphQLContext = + super.generateContext(request).plus( + mapOf("myCustomValue" to (request.headers["my-custom-header"] ?: "defaultContext")) + ) +} + +fun Application.graphQLModule() { + install(GraphQL) { + schema { + packages = listOf("com.example") + queries = listOf(...) + } + server { + contextFactory = CustomGraphQLContextFactory() + } + } + routing { + graphQLPostRoute() + } +} +``` + +Once your application is configured to build your custom GraphQL context, you can then access it through a data fetching +environment argument. While executing the query, data fetching environment will be automatically injected to the function input arguments. +This argument will not appear in the GraphQL schema. + +For more details, see the [Contextual Data Documentation](../../schema-generator/execution/contextual-data.md). + +## Federated Context + +If you need [federation tracing support](../../schema-generator/federation/federation-tracing.md), you can set the appropriate +[configuration properties](./ktor-configuration.md). The provided `DefaultKtorGraphQLContextFactory` populates the required +information for federated tracing, so as long as you extend this context class you will maintain feature support. diff --git a/website/versioned_docs/version-7.x.x/server/ktor-server/ktor-http-request-response.md b/website/versioned_docs/version-7.x.x/server/ktor-server/ktor-http-request-response.md new file mode 100644 index 0000000000..5054275768 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/ktor-server/ktor-http-request-response.md @@ -0,0 +1,67 @@ +--- +id: ktor-http-request-response +title: HTTP request and response +--- + +Ktor HTTP request/response can be intercepted by installing various plugins to your module or by intercepting specific +phases of application call pipeline. By installing `graphql-kotlin-ktor-server` plugin you will configure following pipeline + +```mermaid +flowchart LR + A(Request) --> B(ContentNegotiation) + B --> C(Routing) + C --> D(GraphQL) + D --> E(Response) +``` + +## Installing Additional Plugins + +You can install additional plugins in your module next to the `GraphQL` module. See [Ktor docs](https://ktor.io/docs/plugins.html) +for details. + +```kotlin +fun Application.myModule() { + // install additional plugins + install(CORS) { ... } + install(Authentication) { ... } + + // install graphql plugin + install(GraphQL) { + schema { + packages = listOf("com.example") + queries = listOf(TestQuery()) + } + } + // install authenticated GraphQL routes + install(Routing) { + authenticate("auth-basic") { + graphQLPostRoute() + } + } +} +``` + +## Intercepting Pipeline Phases + +You can intercept requests/responses in various phases of application call pipeline by specifying an interceptor. See +[Ktor docs](https://ktor.io/docs/custom-plugins-base-api.html#call-handling) for details. + +```kotlin +fun Application.myModule() { + install(GraphQL) { + schema { + packages = listOf("com.example") + queries = listOf(TestQuery()) + } + } + install(Routing) { + graphQLPostRoute() + } + + intercept(ApplicationCallPipeline.Monitoring) { + call.request.origin.apply { + println("Request URL: $scheme://$localHost:$localPort$uri") + } + } +} +``` diff --git a/website/versioned_docs/version-7.x.x/server/ktor-server/ktor-overview.mdx b/website/versioned_docs/version-7.x.x/server/ktor-server/ktor-overview.mdx new file mode 100644 index 0000000000..66798dac42 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/ktor-server/ktor-overview.mdx @@ -0,0 +1,106 @@ +--- +id: ktor-overview +title: Ktor Server Overview +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +[graphql-kotlin-ktor-server](https://github.com/ExpediaGroup/graphql-kotlin/tree/master/servers/graphql-kotlin-ktor-server) +is a Ktor Server Plugin that simplifies setup of your GraphQL server. + +## Setup + +The simplest way to create a new Ktor Server app is by generating one using https://start.ktor.io/. + +![Image of https://start.ktor.io/](../../assets/ktor-initializer.png) + +Once you get the sample application setup locally, you will need to add `graphql-kotlin-ktor-server` dependency: + + + + + +```kotlin +implementation("com.expediagroup", "graphql-kotlin-ktor-server", latestVersion) +``` + + + + +```xml + + com.expediagroup + graphql-kotlin-ktor-server + ${latestVersion} + +``` + + + + +## Configuration + +`graphql-kotlin-ktor-server` is a Ktor Server Plugin and you to manually install it in your [module](https://ktor.io/docs/modules.html). + +```kotlin +class HelloWorldQuery : Query { + fun hello(): String = "Hello World!" +} + +fun Application.graphQLModule() { + install(GraphQL) { + schema { + packages = listOf("com.example") + queries = listOf( + HelloWorldQuery() + ) + } + } + install(Routing) { + graphQLPostRoute() + } +} +``` + +If you use `EngineMain` to start your Ktor server, you can specify your module configuration in your `application.conf` (default) +or `application.yaml` (requires additional `ktor-server-config-yaml` dependency) file. + +``` +ktor { + application { + modules = [ com.example.ApplicationKt.graphQLModule ] + } +} +``` + +## Content Negotiation + +:::caution +`graphql-kotlin-ktor-server` automatically configures `ContentNegotiation` plugin with [Jackson](https://github.com/FasterXML/jackson) +serialization for GraphQL GET/POST routes. `kotlinx-serialization` is currently not supported. +::: + +## Routing + +`graphql-kotlin-ktor-server` plugin DOES NOT automatically configure any routes. You need to explicitly configure `Routing` +plugin with GraphQL routes. This allows you to selectively enable routes and wrap them in some additional logic (e.g. `Authentication`). + +GraphQL plugin provides following `Route` extension functions + +- `Route#graphQLGetRoute` - GraphQL route for processing GET query requests +- `Route#graphQLPostRoute` - GraphQL route for processing POST query requests +- `Route#graphQLSDLRoute` - GraphQL route for exposing schema in Schema Definition Language (SDL) format +- `Route#graphiQLRoute` - GraphQL route for exposing [an official IDE](https://github.com/graphql/graphiql) from the GraphQL Foundation + +## GraalVm Native Image Support + +GraphQL Kotlin Ktor Server can be compiled to a [native image](https://www.graalvm.org/latest/reference-manual/native-image/) +using GraalVM Ahead-of-Time compilation. See [Gradle plugin](../../plugins/gradle-plugin-usage-graalvm.mdx) and/or +[Maven plugin](../../plugins/maven-plugin-usage-graalvm.md) documentation for details. diff --git a/website/versioned_docs/version-7.x.x/server/ktor-server/ktor-schema.md b/website/versioned_docs/version-7.x.x/server/ktor-server/ktor-schema.md new file mode 100644 index 0000000000..7026542270 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/ktor-server/ktor-schema.md @@ -0,0 +1,61 @@ +--- +id: ktor-schema +title: Writing Schemas with Ktor +--- + +GraphQL schema, queries and mutation objects have to implement the corresponding marker interface. You can then configure +GraphQL plugin with references to your objects. + +```kotlin +@ContactDirective( + name = "My Team Name", + url = "https://myteam.slack.com/archives/teams-chat-room-url", + description = "send urgent issues to [#oncall](https://yourteam.slack.com/archives/oncall)." +) +@GraphQLDescription("My schema description") +class MySchema : Schema + + +class HelloWorldQuery : Query { + fun hello(): String = "Hello World!" +} + +class UpdateGreetingMutation : Mutation { + fun updateGreeting(greeting: String): String = TODO() +} + +fun Application.graphQLModule() { + install(GraphQL) { + schema { + packages = listOf("com.example") + queries = listOf( + HelloWorldQuery() + ) + mutations = listOf( + UpdateGreetingMutation() + ) + schemaObject = MySchema() + } + } + routing { + graphQLPostRoute() + } +} +``` + +Above code will generate following GraphQL schema + +```graphql +schema @contact(description : "send urgent issues to [#oncall](https://yourteam.slack.com/archives/oncall).", name : "My Team Name", url : "https://myteam.slack.com/archives/teams-chat-room-url"){ + query: Query + mutation: Mutation +} + +type Query { + hello: String! +} + +type Mutation { + updateGreeting(greeting: String!): String! +} +``` diff --git a/website/versioned_docs/version-7.x.x/server/ktor-server/ktor-subscriptions.md b/website/versioned_docs/version-7.x.x/server/ktor-server/ktor-subscriptions.md new file mode 100644 index 0000000000..428f360fb4 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/ktor-server/ktor-subscriptions.md @@ -0,0 +1,60 @@ +--- +id: ktor-subscriptions +title: Subscriptions +--- +_To see more details on how to implement subscriptions in your schema, see the schema generator docs on [executing subscriptions](../../schema-generator/execution/subscriptions.md). +This page lists the `graphql-kotlin-ktor-server` specific features._ + +## Prerequisites + +To start using Subscriptions, you may need install [WebSockets](https://ktor.io/docs/websocket.html) plugin to your Ktor server config. +```kotlin +install(WebSockets) +``` +See [plugin docs](https://ktor.io/docs/websocket.html#configure) to get more info about the `WebSocketOptions` configuration. + +## Flow Support + +`graphql-kotlin-ktor-server` provides support for Kotlin `Flow` by automatically configuring schema generation process with `FlowSubscriptionSchemaGeneratorHooks` +and GraphQL execution with `FlowSubscriptionExecutionStrategy`. + +:::info +If you define your subscriptions using Kotlin `Flow`, make sure to extend `FlowSubscriptionSchemaGeneratorHooks` whenever you need to provide some custom hooks. +::: + +## Subscription Protocols + +### `graphql-transport-ws` subprotocol + +We have implemented subscriptions in Ktor WebSockets following the [`graphql-transport-ws`](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md) sub-protocol +from [The Guild](https://the-guild.dev/). This requires that your client send and parse messages in a specific format. +See protocol documentation for expected messages. + +```kotlin +install(Routing) { + graphQLSubscriptionsRoute() +} +``` + +## Subscription Execution Hooks + +Subscription execution hooks allow you to "hook-in" to the various stages of the connection lifecycle and execute custom logic based on the event. By default, all subscription execution hooks are no-op. +If you would like to provide some custom hooks, you can do so by providing your own implementation of `KtorGraphQLSubscriptionHooks`. + +### `onConnect` +Allows validation of connectionParams prior to starting the connection. +You can reject the connection by throwing an exception. +A `GraphQLContext` returned from this hook will be later passed to subsequent hooks. + +### `onOperation` +Called when the client executes a GraphQL operation. + +### `onOperationComplete` +Called when client's unsubscribes + +### `onDisconnect` +Called when the client disconnects + +## Example + +You can see an example implementation of a `Subscription` in the [example app](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/examples/server/ktor-server/src/main/kotlin/com/expediagroup/graphql/examples/server/ktor/schema/ExampleSubscriptionService.kt). diff --git a/website/versioned_docs/version-7.x.x/server/server-subscriptions.md b/website/versioned_docs/version-7.x.x/server/server-subscriptions.md new file mode 100644 index 0000000000..a9d53eaabb --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/server-subscriptions.md @@ -0,0 +1,13 @@ +--- +id: server-subscriptions +title: Subscriptions +--- + +GraphQL Kotlin provides `WebSocket` subscription support with the generic `Flow` based implementation of [`GraphQL WS` subscription +protocol](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md). Server implementations should extend generic abstract `GraphQLWebSocketServer` class and fill server +specific details on how to read incoming messages from the WebSocket session as well as how to send responses back to the client. + +If you are using one of the official server implementations for GraphQL Kotlin, it will have subscription handling setup for you. + +- See `graphql-kotlin-spring-server` [subscriptions](spring-server/spring-subscriptions.md) +- See `graphql-kotlin-ktor-server` [subscriptions](ktor-server/ktor-subscriptions.md) diff --git a/website/versioned_docs/version-7.x.x/server/spring-server/spring-beans.md b/website/versioned_docs/version-7.x.x/server/spring-server/spring-beans.md new file mode 100644 index 0000000000..81ad73e4c2 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/spring-server/spring-beans.md @@ -0,0 +1,103 @@ +--- +id: spring-beans +title: Automatically Created Beans +--- +`graphql-kotlin-spring-server` automatically creates all the necessary beans to start a GraphQL server. +Many of the beans are conditionally created and the default behavior can be customized by providing custom overriding beans in your application context. + +## Execution + +| Bean | Description | +|:---------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| DataFetcherExceptionHandler | GraphQL exception handler used from the various execution strategies, defaults to [SimpleDataFetcherExceptionHandler](https://www.graphql-java.com/documentation/v16/execution/) from graphql-java. | +| KotlinDataFetcherFactoryProvider | Factory used during schema construction to obtain `DataFetcherFactory` that should be used for target function (using Spring aware `SpringDataFetcher`) and property resolution. | +| KotlinDataLoader (optional) | Any number of beans created that implement `KotlinDataLoader`. See [Data Loaders](../data-loader/data-loader.md) for more details. | +| KotlinDataLoaderRegistryFactory | A factory class that creates a `KotlinDataLoaderRegistry` of all the `KotlinDataLoaders`. Defaults to empty registry. | + +## Non-Federated Schema + +:::note + +_Created only if federation is **disabled**_ + +::: + +| Bean | Description | +|:----------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| GraphQLSchema | GraphQL schema generated based on the schema generator configuration and `Query`, `Mutation` and `Subscription` objects available in the application context. | +| SchemaGeneratorConfig | Schema generator configuration information, see [Schema Generator Configuration](../../schema-generator/customizing-schemas/generator-config.md) for details. Can be customized by providing `TopLevelNames`, [SchemaGeneratorHooks](../../schema-generator/customizing-schemas/generator-config.md) and `KotlinDataFetcherFactoryProvider` beans. | +| GraphQLTypeResolver | GraphQL type resolver that is used to lookup polymorphic type hierarchy. Defaults to use `ClassGraph` to load polymorphic information directly from classpath.

**NOTE: When generating GraalVM Native Images you cannot use classpath scanning and have to explicitly provide this information.** | + +## Federated Schema + +:::note + +_Created only if federation is **enabled**_ + +::: + +| Bean | Description | +|:--------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| FederatedGraphQLTypeResolver | GraphQL type resolver that is used to lookup polymorphic type hierarchy and locate federated entities. Defaults to use `ClassGraph` to load information directly from classpath.

**NOTE: When generating GraalVM Native Images you cannot use classpath scanning and have to explicitly provide this information.** | +| FederatedTypeResolvers | List of `FederatedTypeResolvers` marked as beans that should be added to hooks. See [Federated Type Resolution](../../schema-generator/federation/type-resolution.md) for more details | +| FederatedSchemaGeneratorHooks | Schema generator hooks used to build federated schema | +| FederatedSchemaGeneratorConfig | Federated schema generator configuration information. You can customize the configuration by providing `TopLevelNames`, `FederatedSchemaGeneratorHooks` and `KotlinDataFetcherFactoryProvider` beans | +| FederatedTracingInstrumentation | If `graphql.federation.tracing.enabled` is true, it adds tracing info to the response via the [apollo federation-jvm](https://github.com/apollographql/federation-jvm) library. | +| GraphQLSchema | GraphQL schema generated based on the federated schema generator configuration and `Query`, `Mutation` and `Subscription` objects available in the application context. | + +## GraphQL Configuration + +| Bean | Description | +|:--------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Instrumentation (optional) | Any number of beans created that implement `graphql-java` [Instrumentation](https://www.graphql-java.com/documentation/v16/instrumentation/) will be pulled in. The beans can be ordered by implementing the Spring `Ordered` interface. | +| ExecutionIdProvider (optional) | Any number of beans created that implement `graphql-java` [ExecutionIdProvider](https://github.com/graphql-java/graphql-java/blob/master/src/main/java/graphql/execution/ExecutionIdProvider.java) will be pulled in. | +| PreparsedDocumentProvider (optional) | Any number of beans created that implement `graphql-java` [PreparsedDocumentProvider](https://github.com/graphql-java/graphql-java/blob/master/src/main/java/graphql/execution/preparsed/PreparsedDocumentProvider.java) will be pulled in. | +| GraphQL | GraphQL execution object generated using `GraphQLSchema` with default async execution strategies. The GraphQL object can be customized by optionally providing the above beans in the application context. | +| SpringGraphQLRequestParser | Provides the Spring specific logic for parsing the HTTP request into a common GraphQLRequest. See [GraphQLRequestParser](../graphql-request-parser.md) | +| SpringGraphQLContextFactory | Spring specific factory that uses the `ServerRequest`. The `GraphQLContext` generated can be any object. See [GraphQLContextFactory](../graphql-context-factory.md). | +| GraphQLRequestHandler | Handler invoked from `GraphQLServer` that executes the incoming request, defaults to [GraphQLRequestHandler](../graphql-request-handler.md). | +| SpringGraphQLServer | Spring specific object that takes in a `ServerRequest` and returns a `GraphQLResponse` using all the above implementations. See [GraphQLServer](../graphql-server.md) | +| IDValueUnboxer | Value unboxer that provides support for handling ID value class | + +## Subscriptions + +:::note + +_Created only if the `Subscription` marker interface is used_ + +::: + +| Bean | Description | +|:----------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| FlowSubscriptionSchemaGeneratorHooks | Schema generator hooks that provide support for using `Flow` in your subscriptions | +| WebSocketHandlerAdapter | Spring class for handling web socket http requests. See [Spring documentation](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/reactive/socket/server/support/WebSocketHandlerAdapter.html) | +| HandlerMapping | Maps websocket URL to the corresponding web socket handler | + +### graphql-transport-ws + +| Bean | Description | +|:----------------------------------------|:----------------------------------------------------------------------------------| +| SpringSubscriptionGraphQLContextFactory | Generates GraphQL subscription context based on the WebSocket session information | +| SpringGraphQLSubscriptionRequestParser | Parses incoming WebSocket messages | +| SpringGraphQLSubscriptionHooks | Provides hooks into the subscription request lifecycle | +| SubscriptionWebSocketHandler | WebSocketHandler that implements the `graphql-transport-ws` subscription protocol | + +### (deprecated) subscription-transport-ws + +| Bean | Description | +|:----------------------------------------|:----------------------------------------------------------------------------------------------------------------------| +| ApolloSubscriptionHooks | Provides hooks into the subscription request lifecycle. See [the subscription docs](spring-subscriptions.md) | +| SpringSubscriptionGraphQLContextFactory | Spring specific factory that uses the `WebSocketSession`. See [GraphQLContextFactory](../graphql-context-factory.md). | +| ApolloSubscriptionProtocolHandler | Implementation of the `subscription-transport-ws` subscription protocol | +| ApolloSubscriptionWebSocketHandler | WebSocketHandler that delegates handling of the messages to the `ApolloSubscriptionProtocolHandler` bean | + +## Fixed Beans + +The following beans cannot be overridden, but may have options to disable them: + +- Route handler for GraphQL queries and mutations endpoint. +- Route handler for the SDL endpoint. Created only if sdl route is enabled. +- Route handler for [GraphQL graphiql browser IDE](https://github.com/graphql/graphiql). Created only if graphiql is enabled. +- Route handler for the subscriptions endpoint. Created only if subscriptions are used. +- `ApolloSubscriptionProtocolHandler` for handling GraphQL subscriptions using the [`graphql-ws` protocol](https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md). Created only if subscriptions are used. +- `SubscriptionWebSocketHandler` that utilizes above subscription protocol handler. Created only if subscriptions are used. diff --git a/website/versioned_docs/version-7.x.x/server/spring-server/spring-graphql-context.md b/website/versioned_docs/version-7.x.x/server/spring-server/spring-graphql-context.md new file mode 100644 index 0000000000..97e962532a --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/spring-server/spring-graphql-context.md @@ -0,0 +1,33 @@ +--- +id: spring-graphql-context +title: Generating GraphQL Context +--- +`graphql-kotlin-spring-server` provides a Spring specific implementation of [GraphQLContextFactory](../graphql-context-factory.md) +and the context. + +* `SpringGraphQLContextFactory` - Generates GraphQL context map with federated tracing information per request + +If you are using `graphql-kotlin-spring-server`, you should extend `DefaultSpringGraphQLContextFactory` to automatically +support federated tracing. + +```kotlin +@Component +class MyGraphQLContextFactory : DefaultSpringGraphQLContextFactory() { + override suspend fun generateContext(request: ServerRequest): GraphQLContext = + super.generateContext(request) + mapOf( + "myCustomValue" to (request.headers().firstHeader("MyHeader") ?: "defaultContext") + ) +} +``` + +Once your application is configured to build your custom GraphQL context, you can then access it through a data fetching +environment argument. While executing the query, data fetching environment will be automatically injected to the function input arguments. +This argument will not appear in the GraphQL schema. + +For more details, see the [Contextual Data Documentation](../../schema-generator/execution/contextual-data.md). + +## Federated Context + +If you need [federation tracing support](../../schema-generator/federation/federation-tracing.md), you can set the appropriate [configuration properties](./spring-properties.md). +The provided `DefaultSpringGraphQLContextFactory` populates the required information for federated tracing, so as long as +you extend this context class you will maintain feature support. diff --git a/website/versioned_docs/version-7.x.x/server/spring-server/spring-http-request-response.md b/website/versioned_docs/version-7.x.x/server/spring-server/spring-http-request-response.md new file mode 100644 index 0000000000..db9acb61ea --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/spring-server/spring-http-request-response.md @@ -0,0 +1,7 @@ +--- +id: spring-http-request-response +title: HTTP Request and Response +--- + +To access the HTTP request and response methods, use [Spring WebFilter](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/server/WebFilter.html). +From these filters you can modify the request and response, both before and after the GraphQL execution. diff --git a/website/versioned_docs/version-7.x.x/server/spring-server/spring-overview.mdx b/website/versioned_docs/version-7.x.x/server/spring-server/spring-overview.mdx new file mode 100644 index 0000000000..a3f4dcf899 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/spring-server/spring-overview.mdx @@ -0,0 +1,85 @@ +--- +id: spring-overview +title: Spring Server Overview +--- + + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +[graphql-kotlin-spring-server](https://github.com/ExpediaGroup/graphql-kotlin/tree/master/servers/graphql-kotlin-spring-server) +is a Spring Boot auto-configuration library that automatically configures beans required to start up a reactive GraphQL +web server. + +## WebFlux vs WebMVC + +This library is built on a [Spring WebFlux (reactive)](https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html) stack which is a non-blocking alternative to a traditional [Spring Web MVC (servlet)](https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html) based stack. +Since the frameworks utilize different threading models they cannot and should not be intermixed. +When building a GraphQL server using `graphql-kotlin-spring-server` all your queries and mutations should follow one of the supported [asynchronous execution models](../../schema-generator/execution/async-models.md). + +## Setup + +The simplest way to create a new Kotlin Spring Boot app is by generating one using [Spring Initializr.](https://start.spring.io/) + +![Image of https://start.spring.io/](../../assets/spring-initializer.png) + +Once you get the sample application setup locally, you will need to add `graphql-kotlin-spring-server` dependency: + + + + + +```kotlin +implementation("com.expediagroup", "graphql-kotlin-spring-server", latestVersion) +``` + + + + +```xml + + com.expediagroup + graphql-kotlin-spring-server + ${latestVersion} + +``` + + + + +## Configuration + +At a minimum, in order for `graphql-kotlin-spring-server` to automatically configure your GraphQL web server you need to +specify a list of supported packages that can be scanned for exposing your schema objects through reflections. + +You can do this through the spring application config or by overriding the `SchemaGeneratorConfig` bean. See customization below. + +```yaml +graphql: + packages: + - "com.your.package" +``` + +## Default Routes + +Your newly created GraphQL server starts up with following preconfigured default routes: + +- **/graphql** - GraphQL server endpoint used for processing queries and mutations +- **/subscriptions** - GraphQL server endpoint used for processing subscriptions +- **/sdl** - Convenience endpoint that returns current schema in Schema Definition Language format +- **/graphiql** - [An official IDE](https://github.com/graphql/graphiql) under the GraphQL Foundation + +Note: **/playground** - [Prisma Labs GraphQL Playground IDE](https://github.com/graphql/graphql-playground) endpoint +is still available, but need to be configured through the [Spring Properties](./spring-properties.md) + +## GraalVm Native Image Support + +GraphQL Kotlin Spring Server can be compiled to a [native image](https://www.graalvm.org/latest/reference-manual/native-image/) +using GraalVM Ahead-of-Time compilation. See [Gradle plugin](../../plugins/gradle-plugin-usage-graalvm.mdx) and/or +[Maven plugin](../../plugins/maven-plugin-usage-graalvm.md) documentation for details. diff --git a/website/versioned_docs/version-7.x.x/server/spring-server/spring-properties.md b/website/versioned_docs/version-7.x.x/server/spring-server/spring-properties.md new file mode 100644 index 0000000000..9ac6e3bec0 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/spring-server/spring-properties.md @@ -0,0 +1,34 @@ +--- +id: spring-properties +title: Configuration Properties +--- + +`graphql-kotlin-spring-server` relies +on [GraphQLConfigurationProperties](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/servers/graphql-kotlin-spring-server/src/main/kotlin/com/expediagroup/graphql/server/spring/GraphQLConfigurationProperties.kt) +to provide various customizations of the auto-configuration library. All applicable configuration properties +expose [configuration +metadata](https://docs.spring.io/spring-boot/docs/current/reference/html/configuration-metadata.html) that provide +details on the supported configuration properties. + +| Property | Description | Default Value | +|---------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------|-------------------------------| +| graphql.endpoint | GraphQL server endpoint | graphql | +| graphql.packages | List of supported packages that can contain GraphQL schema type definitions | | +| graphql.printSchema | Boolean flag indicating whether to print the schema after generator creates it | false | +| graphql.federation.enabled | Boolean flag indicating whether to generate federated GraphQL model | false | +| graphql.federation.optInV2 | Boolean flag indicating whether to generate Federation v2 GraphQL model | false | +| graphql.federation.tracing.enabled | Boolean flag indicating whether add federated tracing data to the extensions | true (if federation enabled) | +| graphql.federation.tracing.debug | Boolean flag to log debug info in the federated tracing | false (if federation enabled) | +| graphql.introspection.enabled | Boolean flag indicating whether introspection queries are enabled | true | +| graphql.playground.enabled | Boolean flag indicating whether to enable Prisma Labs Playground GraphQL IDE | false | +| graphql.playground.endpoint | Prisma Labs Playground GraphQL IDE endpoint | playground | +| graphql.graphiql.enabled | Boolean flag indicating whether to enable GraphiQL GraphQL IDE | true | +| graphql.graphiql.endpoint | Prisma Labs Playground GraphQL IDE endpoint | graphiql | +| graphql.sdl.enabled | Boolean flag indicating whether to expose SDL endpoint | true | +| graphql.sdl.endpoint | GraphQL SDL endpoint | sdl | +| graphql.subscriptions.connectionInitTimeout | Server timeout (in milliseconds) between establishing web socket connection and receiving connection-init message | 60_000 | +| graphql.subscriptions.endpoint | GraphQL subscriptions endpoint | subscriptions | +| graphql.subscriptions.keepAliveInterval | **Deprecated**. Keep the websocket alive and send a message to the client every interval in ms. Defaults to not sending messages | null | +| graphql.subscriptions.protocol | WebSocket based subscription protocol. Supported protocols: APOLLO_SUBSCRIPTIONS_WS / GRAPHQL_WS | GRAPHQL_WS | +| graphql.batching.enabled | Boolean flag indicating whether to enable custom dataloader instrumentations for 1 or more GraphQL Operations | false | +| graphql.batching.strategy | Configure which custom dataloader instrumentation will be used (LEVEL_DISPATCHED or SYNC_EXHAUSTION) | LEVEL_DISPATCHED | diff --git a/website/versioned_docs/version-7.x.x/server/spring-server/spring-schema.md b/website/versioned_docs/version-7.x.x/server/spring-server/spring-schema.md new file mode 100644 index 0000000000..fdfc89b3f7 --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/spring-server/spring-schema.md @@ -0,0 +1,94 @@ +--- +id: spring-schema +title: Writing Schemas with Spring +--- + +In order to expose your schema directives, queries, mutations, and subscriptions in the GraphQL schema create beans that +implement the corresponding marker interface and they will be automatically picked up by `graphql-kotlin-spring-server` +auto-configuration library. + +```kotlin +@ContactDirective( + name = "My Team Name", + url = "https://myteam.slack.com/archives/teams-chat-room-url", + description = "send urgent issues to [#oncall](https://yourteam.slack.com/archives/oncall)." +) +@GraphQLDescription("My schema description") +@Component +class MySchema : Schema + +data class Widget(val id: ID, val value: String) + +@Component +class WidgetQuery : Query { + fun widget(id: ID): Widget = getWidgetFromDB(id) +} + +@Component +class WidgetMutation : Mutation { + fun updateWidget(id: ID, value: String): Boolean = updateWidgetInDB(id, value) +} + +@Component +class WidgetSubscription : Subscription { + fun widgetChanges(id: ID): Publisher = getPublisherOfUpdates(id) +} +``` + +will result in a Spring Boot reactive GraphQL web application with following schema. + +```graphql +schema @contact(description : "send urgent issues to [#oncall](https://yourteam.slack.com/archives/oncall).", name : "My Team Name", url : "https://myteam.slack.com/archives/teams-chat-room-url"){ + query: Query + mutation: Mutation + subscription: Subscription +} + +type Widget { + id: ID! + value: String! +} + +type Query { + widget(id: ID!): Widget! +} + +type Mutation { + updateWidget(id: ID!, value: String!): Boolean! +} + +type Subscription { + widgetChanges(id: ID!): Widget! +} +``` + +## Spring Beans + +Since the top level objects are Spring components, Spring will automatically autowire dependent beans as normal. Refer to [Spring Documentation](https://docs.spring.io/spring/docs/current/spring-framework-reference/) for details. + +```kotlin +@Component +class WidgetQuery(private val repository: WidgetRepository) : Query { + fun getWidget(id: Int): Widget = repository.findWidget(id) +} +``` + +## Spring Beans in Arguments + +`graphql-kotlin-spring-server` provides Spring-aware data fetcher that automatically autowires Spring beans when they are +specified as function arguments. `@Autowired` arguments should be explicitly excluded from the GraphQL schema by also +specifying `@GraphQLIgnore`. + +```kotlin +@Component +class SpringQuery : Query { + fun getWidget(@GraphQLIgnore @Autowired repository: WidgetRepository, id: Int): Widget = repository.findWidget(id) +} +``` + +:::note +If you are using custom data fetcher make sure that you extend `SpringDataFetcher` instead of the base `FunctionDataFetcher` to keep this functionallity. +::: + +We have examples of these techniques implemented in Spring boot in the [example +app](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/examples/server/spring-server/src/main/kotlin/com/expediagroup/graphql/examples/server/spring/query/NestedQueries.kt). diff --git a/website/versioned_docs/version-7.x.x/server/spring-server/spring-subscriptions.md b/website/versioned_docs/version-7.x.x/server/spring-server/spring-subscriptions.md new file mode 100644 index 0000000000..db6524e41f --- /dev/null +++ b/website/versioned_docs/version-7.x.x/server/spring-server/spring-subscriptions.md @@ -0,0 +1,61 @@ +--- +id: spring-subscriptions +title: Subscriptions +--- +_To see more details on how to implement subscriptions in your schema, see the schema generator docs on [executing subscriptions](../../schema-generator/execution/subscriptions.md). +This page lists the `graphql-kotlin-spring-server` specific features._ + +## Flow Support + +`graphql-kotlin-spring-server` provides automatic support for Kotlin `Flow` by automatically configuring `FlowSubscriptionSchemaGeneratorHooks` +and `FlowSubscriptionExecutionStrategy` beans. + +:::info +If you define your subscriptions using Kotlin `Flow`, make sure to extend `FlowSubscriptionSchemaGeneratorHooks` whenever you need to provide some custom hooks. +::: + +## Subscription Protocols + +### `graphql-transport-ws` subprotocol + +We have implemented subscriptions in Spring WebSockets following the [`graphql-transport-ws` subprotocol](https://github.com/enisdenjo/graphql-ws) +from [The Guild](https://the-guild.dev/). This requires that your client send and parse messages in a specific format. +See protocol documentation for expected messages. + +`graphql-transport-ws` is the default subscription protocol that is enabled by default. + +### (deprecated) `subscriptions-transport-ws` subprotocol + +:::caution +`subscriptions-transport-ws` was deprecated in favor of [`graphql-transport-ws` protocol](https://github.com/enisdenjo/graphql-ws). +::: + +We have implemented subscriptions in Spring WebSockets following the [`subscriptions-transport-ws` subprotocol](https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md) +defined by [Apollo](https://www.apollographql.com/). This requires that your client send and parse messages in a specific +format. See protocol documentation for expected messages. + +`subscription-transport-ws` is deprecated. In order to use it, you need to explicitly opt-in by specifying `graphql.subscriptions.protocol=APOLLO_SUBSCRIPTIONS_WS` +configuration property. Support for this protocol will be removed in the next major release. + +## Subscription Hooks + +In line with the Apollo protocol, we have implemented hooks to execute functions at different stages of the connection lifecycle. +If you would like to implement your own subscription hooks, you can provide a primary spring bean for `ApolloSubscriptionHooks` that overrides the [default one](./spring-beans.md) which do not perform any actions. + +### `onConnect` / `onConnectWithContext` +Allows validation of connectionParams prior to starting the connection. +You can reject the connection by throwing an exception. +If you need to forward state to execution, update and return the [GraphQLContext](./spring-graphql-context.md). + +### `onOperation` / `onOperationWithContext` +Called when the client executes a GraphQL operation. The context can not be updated here, it is read only. + +### `onOperationComplete` +Called when client's unsubscribes + +### `onDisconnect` +Called when the client disconnects + +## Example + +You can see an example implementation of a `Subscription` in the [example app](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/examples/server/spring-server/src/main/kotlin/com/expediagroup/graphql/examples/server/spring/subscriptions/SimpleSubscription.kt). diff --git a/website/versioned_sidebars/version-7.x.x-sidebars.json b/website/versioned_sidebars/version-7.x.x-sidebars.json new file mode 100644 index 0000000000..5f199193d4 --- /dev/null +++ b/website/versioned_sidebars/version-7.x.x-sidebars.json @@ -0,0 +1,140 @@ +{ + "docs": { + "Introduction": [ + "getting-started", + "examples", + "framework-comparison", + "blogs-and-videos" + ], + "Schema Generator": [ + "schema-generator/schema-generator-getting-started", + { + "type": "category", + "label": "Writing schemas with Kotlin", + "items": [ + "schema-generator/writing-schemas/schema", + "schema-generator/writing-schemas/fields", + "schema-generator/writing-schemas/nullability", + "schema-generator/writing-schemas/arguments", + "schema-generator/writing-schemas/scalars", + "schema-generator/writing-schemas/enums", + "schema-generator/writing-schemas/lists", + "schema-generator/writing-schemas/interfaces", + "schema-generator/writing-schemas/unions", + "schema-generator/writing-schemas/nested-arguments" + ] + }, + { + "type": "category", + "label": "Customizing Schema", + "items": [ + "schema-generator/customizing-schemas/annotations", + "schema-generator/customizing-schemas/generator-config", + "schema-generator/customizing-schemas/documenting-schema", + "schema-generator/customizing-schemas/excluding-fields", + "schema-generator/customizing-schemas/renaming-fields", + "schema-generator/customizing-schemas/directives", + "schema-generator/customizing-schemas/deprecating-schema", + "schema-generator/customizing-schemas/custom-type-reference", + "schema-generator/customizing-schemas/restricting-input-output", + "schema-generator/customizing-schemas/advanced-features" + ] + }, + { + "type": "category", + "label": "Execution", + "items": [ + "schema-generator/execution/fetching-data", + "schema-generator/execution/async-models", + "schema-generator/execution/exceptions", + "schema-generator/execution/data-fetching-environment", + "schema-generator/execution/contextual-data", + "schema-generator/execution/optional-undefined-arguments", + "schema-generator/execution/subscriptions", + "schema-generator/execution/introspection" + ] + }, + { + "type": "category", + "label": "Federation", + "items": [ + "schema-generator/federation/apollo-federation", + "schema-generator/federation/federated-schemas", + "schema-generator/federation/federated-directives", + "schema-generator/federation/type-resolution", + "schema-generator/federation/federation-tracing" + ] + } + ], + "Server": [ + "server/graphql-server", + "server/graphql-request-parser", + "server/graphql-context-factory", + "server/graphql-request-handler", + "server/server-subscriptions", + "server/automatic-persisted-queries/automatic-persisted-queries", + { + "type": "category", + "label": "Data Loader", + "items": [ + "server/data-loader/data-loader", + "server/data-loader/data-loader-instrumentation" + ] + }, + { + "type": "category", + "label": "Spring Server", + "items": [ + "server/spring-server/spring-overview", + "server/spring-server/spring-schema", + "server/spring-server/spring-graphql-context", + "server/spring-server/spring-http-request-response", + "server/spring-server/spring-beans", + "server/spring-server/spring-properties", + "server/spring-server/spring-subscriptions" + ] + }, + { + "type": "category", + "label": "Ktor Server Plugin", + "items": [ + "server/ktor-server/ktor-overview", + "server/ktor-server/ktor-schema", + "server/ktor-server/ktor-graphql-context", + "server/ktor-server/ktor-http-request-response", + "server/ktor-server/ktor-configuration", + "server/ktor-server/ktor-subscriptions" + ] + } + ], + "Client": [ + "client/client-overview", + "client/client-features", + "client/client-customization", + "client/client-serialization" + ], + "Build Plugins": [ + { + "type": "category", + "label": "Gradle Plugin", + "items": [ + "plugins/gradle-plugin-tasks", + "plugins/gradle-plugin-usage-client", + "plugins/gradle-plugin-usage-sdl", + "plugins/gradle-plugin-usage-graalvm" + ] + }, + { + "type": "category", + "label": "Maven Plugin", + "items": [ + "plugins/maven-plugin-goals", + "plugins/maven-plugin-usage-client", + "plugins/maven-plugin-usage-sdl", + "plugins/maven-plugin-usage-graalvm" + ] + }, + "plugins/hooks-provider" + ] + } +} diff --git a/website/versions.json b/website/versions.json index 2cd029d0f1..592e110065 100644 --- a/website/versions.json +++ b/website/versions.json @@ -1,4 +1,5 @@ [ + "7.x.x", "6.x.x", "5.x.x", "4.x.x",