From 6484f41890216a48ebdc823f17afa59a4e3983d5 Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Tue, 24 Dec 2024 11:40:46 +0300 Subject: [PATCH 1/6] Improve documentation of `@cacheControl` --- .../performance/response-caching.mdx | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx b/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx index 0d23ef6955..f24402d359 100644 --- a/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx +++ b/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx @@ -67,6 +67,43 @@ for the fields and types they are defining. You can add this directive during co - [See here for Federation to learn more about the `@cacheControl` directive](https://www.apollographql.com/docs/federation/performance/caching/#using-cache-hints-with-subgraphs) - [See here for GraphQL Mesh to learn more about the `@cacheControl` in subgraph definitions](/docs/gateway/other-features/performance/response-caching) +### `@cacheControl` directive + +In Apollo Server, `@cacheControl` directive is used to configure the behavior of the response +headers including `cache-control` of the subgraph server. And in this case, you can just use +[HTTP Caching plugin](/docs/gateway/other-features/performance/http-caching) to handle caching +headers. If you want to use that approach with Apollo Server, check the relevant docs +[here](https://www.apollographql.com/docs/apollo-server/performance/caching). + +But in Hive Gateway, it is possible to handle those directives on the gateway level to configure +response caching of the gateway from the subgraph. In this case, you need to expose `@cacheControl` +directive to the supergraph by adding the following definitions; + +```graphql +extend schema + @link( + # Federation spec version should be at least 2.1 to support `@composeDirective` + url: "https://specs.apollo.dev/federation/v2.1" + import: ["@composeDirective"] + ) + # Import `@cacheControl` + @link(url: "https://the-guild.dev/mesh/v1.0", import: ["@cacheControl"]) + # Use `@composeDirective` to define the directive as exposed + @composeDirective(name: "@cacheControl") + +# Then add the actual directive definitions +enum CacheControlScope { + PUBLIC + PRIVATE +} + +directive @cacheControl( + maxAge: Int + scope: CacheControlScope + inheritMaxAge: Boolean +) on FIELD_DEFINITION | OBJECT | INTERFACE | UNION +``` + ## Session based caching If your GraphQL API returns specific data depending on the viewer's session, you can use the session From 7a96fb31203ed29bef1454aed4af844b8ba70d2e Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Tue, 24 Dec 2024 14:05:04 +0300 Subject: [PATCH 2/6] More --- .../performance/response-caching.mdx | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx b/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx index f24402d359..14dd68428d 100644 --- a/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx +++ b/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx @@ -69,15 +69,27 @@ for the fields and types they are defining. You can add this directive during co ### `@cacheControl` directive -In Apollo Server, `@cacheControl` directive is used to configure the behavior of the response +This directive allows you to control response caching from the subgraph. But its behavior is +different in different gateway and subgraph implementations. In GraphQL Yoga, `@cacheControl` +directive is used to configure the behavior of the response caching plugin, and the response caching +plugin uses `ETag` headers, not `Cache-Control` headers so it can be automatically invalidated by +mutations. Unlike GraphQL Yoga, Apollo Server uses `Cache-Control` directives to set the caching +behavior of the response headers without `ETag` headers and it doesn't validate the cached response +by the client. + +As Apollo Server handles `@cacheControl` directives to configure the behavior of the response headers including `cache-control` of the subgraph server. And in this case, you can just use [HTTP Caching plugin](/docs/gateway/other-features/performance/http-caching) to handle caching headers. If you want to use that approach with Apollo Server, check the relevant docs [here](https://www.apollographql.com/docs/apollo-server/performance/caching). -But in Hive Gateway, it is possible to handle those directives on the gateway level to configure -response caching of the gateway from the subgraph. In this case, you need to expose `@cacheControl` -directive to the supergraph by adding the following definitions; +If you use GraphQL Yoga, you don't have an extra configuration like above unless you want to have +another caching layer on the gateway. + +In order to let the gateway handle the caching behavior rather than the subgraph server, it is +possible to handle those directives on the Hive Gateway level to configure response caching of the +gateway from the subgraph. In this case, you need to expose `@cacheControl` directive to the +supergraph by adding the following definitions; ```graphql extend schema From 5878bc3a90cbfa995d987c331ac3417b3217ac3f Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Tue, 24 Dec 2024 14:06:01 +0300 Subject: [PATCH 3/6] Links --- .../performance/response-caching.mdx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx b/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx index 14dd68428d..ae82953d83 100644 --- a/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx +++ b/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx @@ -70,12 +70,16 @@ for the fields and types they are defining. You can add this directive during co ### `@cacheControl` directive This directive allows you to control response caching from the subgraph. But its behavior is -different in different gateway and subgraph implementations. In GraphQL Yoga, `@cacheControl` -directive is used to configure the behavior of the response caching plugin, and the response caching -plugin uses `ETag` headers, not `Cache-Control` headers so it can be automatically invalidated by -mutations. Unlike GraphQL Yoga, Apollo Server uses `Cache-Control` directives to set the caching -behavior of the response headers without `ETag` headers and it doesn't validate the cached response -by the client. +different in different gateway and subgraph implementations. + +In GraphQL Yoga, `@cacheControl` directive is used to configure the behavior of the response caching +plugin, and the response caching plugin uses `ETag` headers, not `Cache-Control` headers so it can +be automatically invalidated by mutations. +[Learn more here](https://the-guild.dev/graphql/yoga-server/docs/features/response-caching). + +Unlike GraphQL Yoga, Apollo Server uses `Cache-Control` directives to set the caching behavior of +the response headers without `ETag` headers and it doesn't validate the cached response by the +client. [Learn more here](https://www.apollographql.com/docs/apollo-server/performance/caching). As Apollo Server handles `@cacheControl` directives to configure the behavior of the response headers including `cache-control` of the subgraph server. And in this case, you can just use From 99a9b919bf026bcfc87d7f03aa9353ae2811c276 Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Mon, 6 Jan 2025 16:31:50 +0300 Subject: [PATCH 4/6] Charts --- .../performance/response-caching.mdx | 146 +++++++++++++++--- 1 file changed, 121 insertions(+), 25 deletions(-) diff --git a/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx b/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx index ae82953d83..7f37dc887d 100644 --- a/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx +++ b/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx @@ -69,31 +69,127 @@ for the fields and types they are defining. You can add this directive during co ### `@cacheControl` directive -This directive allows you to control response caching from the subgraph. But its behavior is -different in different gateway and subgraph implementations. - -In GraphQL Yoga, `@cacheControl` directive is used to configure the behavior of the response caching -plugin, and the response caching plugin uses `ETag` headers, not `Cache-Control` headers so it can -be automatically invalidated by mutations. -[Learn more here](https://the-guild.dev/graphql/yoga-server/docs/features/response-caching). - -Unlike GraphQL Yoga, Apollo Server uses `Cache-Control` directives to set the caching behavior of -the response headers without `ETag` headers and it doesn't validate the cached response by the -client. [Learn more here](https://www.apollographql.com/docs/apollo-server/performance/caching). - -As Apollo Server handles `@cacheControl` directives to configure the behavior of the response -headers including `cache-control` of the subgraph server. And in this case, you can just use -[HTTP Caching plugin](/docs/gateway/other-features/performance/http-caching) to handle caching -headers. If you want to use that approach with Apollo Server, check the relevant docs -[here](https://www.apollographql.com/docs/apollo-server/performance/caching). - -If you use GraphQL Yoga, you don't have an extra configuration like above unless you want to have -another caching layer on the gateway. - -In order to let the gateway handle the caching behavior rather than the subgraph server, it is -possible to handle those directives on the Hive Gateway level to configure response caching of the -gateway from the subgraph. In this case, you need to expose `@cacheControl` directive to the -supergraph by adding the following definitions; +This directive allows you to control response caching from the subgraph. But the behavior can be +different depending on the subgraph configuration. + +#### Apollo Server with `Cache-Control` header + +Apollo Server handles `@cacheControl` directives to set HTTP caching headers in the HTTP response to +the gateway. Then the gateway can cache the response based on these headers. +[Learn more about Apollo Server's cache control behavior](https://www.apollographql.com/docs/apollo-server/performance/caching). +In this case, gateway is still response of caching the response. Hive Gateway can handle http +caching headers using [HTTP Caching plugin](/docs/gateway/other-features/performance/http-caching). + +```mermaid +flowchart TD + A["GraphQL Client"] -->|"GraphQL Request"| B(Go shopping) + B("Hive Gateway") --> C{Let me think} + C -->|"Cache Hit"| D["Get the cached response from Cache Storage"] + C -->|"Not Cached"| E["Send HTTP Response Back"] + C{"Subgraph Executor"} + D ---|"Return the cached response"| C + E + E ---|"Get 'Cache-Control' header, and store the response for the following requests"| C{"Subgraph Executor gets the query"} +``` + +##### Example + +Let's say you have a subgraph that defines a `Post` type with a `@cacheControl` directive, your Hive +Gateway has [HTTP Caching plugin](/docs/gateway/other-features/performance/http-caching) enabled. + +```graphql +type Post @cacheControl(maxAge: 240) { + id: Int! + title: String +} +``` + +When the gateway receives a query that selects the `Post` type, it will cache the response for 240 +seconds. + +```graphql +query { + posts { + id + title + } +} +``` + +In this case, the gateway will cache the response for 240 seconds. If the same query is made within +240 seconds, the gateway will return the cached response. + +#### GraphQL Yoga with the response caching plugin + +On the other hand, GraphQL Yoga handles `@cacheControl` directives to configure the response caching +behavior rather than `Cache-Control` headers like Apollo Server. It leverages `ETag` headers to +cache the response and invalidate it by mutations. +[Learn more about GraphQL Yoga's response caching behavior](https://the-guild.dev/graphql/yoga-server/docs/features/response-caching). +So even if nothing is configured on the gateway but Yoga on the subgraph uses the response caching +plugin on its own. But this won't reduce the HTTP connection traffic in between gateway and +subgraph. + +```mermaid +flowchart TD + A["GraphQL Client"] + B(Go shopping) + B("Hive Gateway") + E["Send HTTP Response Back"] + E + E["Subgraph Yoga Server"] + E --- n1["Response Cache Plugin"] + n1 ---|"If Cached"| n2["Get the cached response from Cache Storage"] + n1 ---|"If Not Cached"| n3["Prepare the result by making database calls etc, and store it for the future calls"] + subgraph B["Hive Gateway"] + n5 + n4["Query Planner"] + end + n4 + n4 ---|"Generate Subgraph Query"| n5["Execution Engine"] + n5 + E + B + n5 + n5 + n5 ---|"HTTP Request"| E + A --- B +``` + +##### Example + +Let's say you have a subgraph that defines a `Post` type with a `@cacheControl` directive, your Hive +Gateway has [HTTP Caching plugin](/docs/gateway/other-features/performance/http-caching) enabled. + +```graphql +type Post @cacheControl(maxAge: 240) { + id: Int! + title: String +} +``` + +When the gateway receives a query that selects the `Post` type, it will forward the request to the +subgraph directly. + +```graphql +query { + posts { + id + title + } +} +``` + +Then Yoga Server will generate the response and cache it for 240 seconds. If the same query is made +within 240 seconds, Yoga Server will return the cached response. So it will always receive the HTTP +request but do the less work to generate the response. The difference between others, this case +won't reduce the HTTP connection traffic in between gateway and subgraph, but it will reduce the +work that subgraph needs to do to generate the response. + +#### Subgraphs with any server implementation using directives directly + +Besides these two, you can let the gateway handle the caching on its own. In this case, you need to +define the following in the subgraphs so the supergraph has `@cacheControl` directives. Then, the +response caching plugin on the gateway will handle the caching based on these directives. ```graphql extend schema From f8a44d0f7b6e66566652b70dfd3f566e5a39e979 Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Mon, 6 Jan 2025 16:32:03 +0300 Subject: [PATCH 5/6] .. --- .../performance/response-caching.mdx | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx b/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx index 7f37dc887d..1670d0f68c 100644 --- a/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx +++ b/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx @@ -216,6 +216,47 @@ directive @cacheControl( ) on FIELD_DEFINITION | OBJECT | INTERFACE | UNION ``` +In this case, the gateway will cache the response based on the `@cacheControl` directives defined in +the subgraphs. + +The difference between the two is that the gateway will control the caching behavior based on the +`@cacheControl` directives defined in the subgraphs. For any cached responses, the gateway will skip +query planning and federation execution phase, and return the response directly. + +```mermaid +flowchart TD + A["GraphQL Client"] + B(Go shopping) + B("Hive Gateway") + E["Send HTTP Response Back"] + E + E["Subgraph Yoga Server"] + E --- n1["Response Cache Plugin"] + n1 ---|"If Cached"| n2["Get the cached response from Cache Storage"] + n1 ---|"If Not Cached"| n3["Prepare the result by making database calls etc, and store it for the future calls"] + subgraph B["Hive Gateway"] + n7["Get Stored Response"] + n6["Response Caching Plugin"] + n5 + n4["Query Planner"] + end + n4 + n4 ---|"Generate Subgraph Query"| n5["Execution Engine"] + n5 + E + B + n5 + n5 + n5 ---|"HTTP Request"| E + A + B + n6 ---|"If Not Cached"| n4 + n6 ---|"If Cache Hit"| n7 + n7 ---|"Respond Cached Response back to Client"| A + n5 ---|"Store the response for future calls"| n6 + A ---|"Send GraphQL Request via HTTP "| n6 +``` + ## Session based caching If your GraphQL API returns specific data depending on the viewer's session, you can use the session From 1f31e57ffc1f2b5d67d1d5d612b38251b6a938a4 Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Mon, 6 Jan 2025 16:37:09 +0300 Subject: [PATCH 6/6] .. --- .../performance/response-caching.mdx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx b/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx index 1670d0f68c..5bb96bed0a 100644 --- a/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx +++ b/packages/web/docs/src/pages/docs/gateway/other-features/performance/response-caching.mdx @@ -64,15 +64,19 @@ The behaviour of this plugin can be configured by passing an object at the gatew The `@cacheControl` directive can be used to give to subgraphs the control over the cache behavior for the fields and types they are defining. You can add this directive during composition. -- [See here for Federation to learn more about the `@cacheControl` directive](https://www.apollographql.com/docs/federation/performance/caching/#using-cache-hints-with-subgraphs) -- [See here for GraphQL Mesh to learn more about the `@cacheControl` in subgraph definitions](/docs/gateway/other-features/performance/response-caching) +You can learn more about the behavior of the `@cacheControl` directive in the following section. If +you want to use the configuration API on the gateway, you can skip the `@cacheControl` directive +section. -### `@cacheControl` directive +### `@cacheControl` directive's behavior This directive allows you to control response caching from the subgraph. But the behavior can be different depending on the subgraph configuration. -#### Apollo Server with `Cache-Control` header +The following 3 section shows the ways of using the `@cacheControl` directive in different ways. The +usage examples in the other sections represent the third(last) use case in the following three. + +#### Apollo Server with `Cache-Control` header (This response cache plugin is not required) Apollo Server handles `@cacheControl` directives to set HTTP caching headers in the HTTP response to the gateway. Then the gateway can cache the response based on these headers. @@ -119,7 +123,7 @@ query { In this case, the gateway will cache the response for 240 seconds. If the same query is made within 240 seconds, the gateway will return the cached response. -#### GraphQL Yoga with the response caching plugin +#### GraphQL Yoga with the response caching plugin (This response cache plugin is not required) On the other hand, GraphQL Yoga handles `@cacheControl` directives to configure the response caching behavior rather than `Cache-Control` headers like Apollo Server. It leverages `ETag` headers to @@ -185,7 +189,7 @@ request but do the less work to generate the response. The difference between ot won't reduce the HTTP connection traffic in between gateway and subgraph, but it will reduce the work that subgraph needs to do to generate the response. -#### Subgraphs with any server implementation using directives directly +#### Subgraphs with any server implementation using directives directly (This response cache plugin is required) Besides these two, you can let the gateway handle the caching on its own. In this case, you need to define the following in the subgraphs so the supergraph has `@cacheControl` directives. Then, the