Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

docs: updated doc for field and entity caching #104

Merged
merged 4 commits into from
Feb 13, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 107 additions & 15 deletions docs/operators/cache.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,129 @@
title: "@cache"
---

The **@cache** operator enables caching for the query, field or type it is applied to. For eg:
The **@cache** directive provides a protocol agnostic mechanism for caching the results of fields within a GraphQL schema. Like any other cache implementation this feature is useful for optimizing performance by reducing the need to repeatedly fetch data that doesn't change frequently.

## maxAge

```graphql
@cache(maxAge: Int)
```

This parameter is a non-zero unsigned integer that specifies the duration, in milliseconds, for which the cached value should be retained.

## Usage

Consider the following GraphQL schema example:

```graphql
type Query {
posts: [Post] @http(path: "/posts")
}

type Post {
id: Int
title: String
userId: Int @cache(maxAge: 100)
user: User @http(path: "/user/{{value.userId}}") @cache(maxAge: 200)
}

type User {
id: Int
name: String
email: String
}
```

In this configuration, the result of the `user` field will be cached because it is associated with an HTTP resolver. However, the values of `userId` and `title` will not be cached as they do not have their own resolvers; their values are retrieved by the resolver at the `posts` field, which utilizes the `@http(path: "/posts")` directive.

Applying the `@cache` directive at the type level affects all fields within that type. For example:

```graphql
type Query {
posts: [Post] @http(path: "/posts")
}

type Post @cache(maxAge: 100) {
id: Int
title: String
userId: Int
user: User @http(path: "/user/{{value.userId}}")
}

type User {
id: Int
name: String
email: String
}
```

This configuration can be reduced as follows, demonstrating that the `@cache` directive, when applied to a type, is inherited by each field within that type:

```graphql
schema {
query: Query
type Query {
posts: [Post] @http(path: "/posts")
}

type Post {
id: Int @cache(maxAge: 100)
title: String @cache(maxAge: 100)
userId: Int @cache(maxAge: 100)
user: User @http(path: "/user/{{value.userId}}") @cache(maxAge: 100)
}

type User {
id: Int
name: String
email: String
}
```

However, since the `@cache` directive does not affect fields without resolvers, the effective configuration can be further reduced to follows:

```graphql
type Query {
posts: [Post] @cache(maxAge: 3000)
user(id: Int): User
posts: [Post] @http(path: "/posts")
}

type Post {
id: Int
title: String
body: String
user: User
userId: Int
user: User @http(path: "/user/{{value.userId}}") @cache(maxAge: 100)
}

type User @cache(maxAge: 4000) {
type User {
id: Int
name: String @cache(maxAge: 8000)
age: Int
name: String
email: String
}
```

## maxAge
When the `@cache` directive is applied both at the type level and on individual fields within that type, the field-level directive takes precedence:

```graphql
type Query {
posts: [Post] @http(path: "/posts")
}

type Post @cache(maxAge: 200) {
id: Int
title: String
userId: Int
user: User @http(path: "/user/{{value.userId}}") @cache(maxAge: 100)
}

type User {
id: Int
name: String
email: String
}
```

the parameter `maxAge` takes a non-zero unsigned integer value which signifies the duration, in milliseconds, for which the value will be cached.
Thus, in the configuration above, while the `@cache(maxAge: 200)` directive at the type level is inherited by all fields, the `user` field's explicit `@cache(maxAge: 100)` directive takes precedence.

In the above example, the entire result of `posts` query will be cached for 3000ms. When the **@cache** operator is applied to a type, it is equivalent to applying it to each field individually. If for a type, one of the fields needs to be cached differently then this operator can be applied to that field separately and it will override the values provided for the type, as can be seen in the above example for `name` field in the `User` type.
## Cache Key

# How does the caching work?
The caching mechanism generates a hash based on information related to the applied query to serve as the cache key for the corresponding value.

If **@cache** is set for a query or a field, the resolver for it will run once and the result will be stored in memory for `maxAge` milliseconds, and will expire after this duration. After the cache expires, the resolver will be run again to fetch the latest value and that value will then be cached.
For instance, the `user` field in the following configuration will be cached, with the cache key being the hash of the interpolated string `"/user/{{value.userId}}"`. For example, if `Post.userId` equals `1`, the cache key will be the hash of the string `"/users/1"`.
Loading