import { Callout } from '@theguild/components'

# Cache Transform

The `cache` transform allows you to easily apply caching over your data sources.

It allows you to configure custom invalidation rules (by TTL/mutation) and selective caching according to your needs.

<Callout>
  This transform is being applied globally because of the need to communicate with other GraphQL operations from your
  mesh.
</Callout>

To get started with this transform, install it:

```sh npm2yarn
npm i @graphql-mesh/transform-cache
```

<Callout>
  GraphQL Mesh uses a default localForage cache (it is fallback to LRU cache in NodeJS), but you can replace it with any other key=>value cache mechanism. See [cache section](/docs/cache/localforage) for more info.
  We'd recommend this transform be used on the root level, not the handler level. It might not work as expected if you use it on a handler level.

</Callout>

## How to use?

### Simple caching

To cache some of your queries, apply the following transform rule. The following example will cache all `Query.*` in your schema forever:

```yaml filename=".meshrc.yaml"
transforms:
  - cache:
      - field: Query.*
```

You can also apply it to a specific field or multiple fields:

```yaml filename=".meshrc.yaml"
transforms:
  - cache:
      - field: Query.users
  - cache:
      - field: Query.posts
```

### The Cache Key

Each cache record is stored with a key. The default way of creating this key is to use the GraphQL type name, the GraphQL field name, and a hash of the `args` object. This is in order to make that we can distinct the cache key according to the data it's storing.

You can customize the `cacheKey` according to your needs, and you can use custom helpers to help you create those cache keys dynamically.

The following example creates a `cacheKey` by a GraphQL query argument called `userId` per day:

```yaml filename=".meshrc.yaml"
transforms:
  - cache:
      - field: Query.user
        cacheKey: user-{args.id}-{yyyy-mm-dd | date}
```

## Cache Invalidation

### TTL

Invalidation by TTL is the simplest way to deal with your cache. You can specify any time (in seconds) to keep your cache.

```yaml filename=".meshrc.yaml"
transforms:
  - cache:
      - field: Query.*
        invalidate:
          ttl: 3600 # 1 hour
```

### Operation-based

GraphQL Mesh has a built-in operation-based caching solution.

You can cache data easily and invalidate it only when it changes by a mutation.

For example, given the following schema:

```graphql
type Query {
  user(id: ID!): User!
}

type Mutation {
  updateUser(userIdToUpdate: ID!, setFields: UpdateUserInput!): User!
}

type User {
  id: ID!
  email: String!
  name: String
}

input UpdateUserInput {
  email: String
  name: String
}
```

You can set a simple caching based on a user id:

```yaml filename=".meshrc.yaml"
transforms:
  - cache:
      - field: Query.user
        cacheKey: user-{args.id}
```

And you can add operation-based invalidation, so when `updateUser` is done successfully, it will invalidate the matching cache record to make sure the data will be fetched next time from the remote source:

```yaml filename=".meshrc.yaml"
transforms:
  - cache:
      - field: Query.user
        cacheKey: user-{args.id}
        invalidate:
          effectingOperations:
            - operation: Mutation.updateUser
              matchKey: user-{args.userIdToUpdate}
```

This way, when someone uses `updateUser` with a specific user id, it will automatically update the data record and then invalidate the cache

### Programmatic

The `getBuiltMesh` method of GraphQL Mesh artifacts returns the general key=>value cache it uses at the moment, so you can easily access it and invalidate records according to your needs:

```ts
const { getBuiltMesh } = require('./.mesh')
const { schema, execute, cache } = getBuiltMesh()

cache.delete(SOME_KEY)
```

## CodeSandBox Example

You can check the ["Location Weather" example](https://github.com/Urigo/graphql-mesh/tree/master/examples/openapi-location-weather/) that uses OpenAPI handler with cache transform;

<iframe
  src="https://codesandbox.io/embed/github/Urigo/graphql-mesh/tree/master/examples/openapi-location-weather?fontsize=14&hidenavigation=1&theme=dark&module=%2F.meshrc.yml"
  className="mt-6 w-full h-[500px] rounded-md"
  title="typescript-location-weather-example"
  allow="geolocation; microphone; camera; midi; vr; accelerometer; gyroscope; payment; ambient-light-sensor; encrypted-media; usb"
  sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"
/>

## Config API Reference

import API from '../../../generated-markdown/CacheTransformConfig.generated.md'

<API />
