Performance & Caching
Hive Gateway provides a set of features to help you optimize the performance of your GraphQL gateway. Hive Gateway provides a shared caching storage that can be used across plugins, transforms, subgraph execution and remote schema caching.
If you are running Hive Gateway serverless on the edge, you’re highly advised to provide a cache. Aside from all of the aforementioned benefits, the biggest one is caching the remote schema so that it does not get pulled on each request.
Providing Cache Storage
In order to enable features that need a storage to keep the data, you need to define a cache storage implementation, and pass it to the gateway.
You can choose the best-fit cache storage for your use case.
LocalForage
LocalForage is a library that improves the existing storage mechanism in the browser by using
IndexedDB
, WebSQL
and localStorage
, see more.
Even if it is known as a browser storage, Hive Gateway provides you as a platform-agnostic cache storage to leverage the well-known storage APIs that are available in most JavaScript environments.
import { defineConfig } from '@graphql-hive/gateway'
export const gatewayConfig = defineConfig({
cache: {
type: 'localforage',
// All of the following options are listed with default values, you don't need to provide them
driver: ['WEBSQL', 'INDEXEDDB', 'LOCALSTORAGE'] // The order of the drivers to use
name: 'HiveGateway', // The name of the database
version: 1.0, // The version of the database
size: 4980736, // The size of the database
storeName: 'keyvaluepairs', // The name of the store
description: 'Cache storage for Hive Gateway', // The description of the database
}
responseCaching: {
session: () => null,
}
})
Redis
Redis is an in-memory data structure store, used as a database, cache, and message broker. You can use Redis as a cache storage for your Hive Gateway.
import { defineConfig } from '@graphql-hive/gateway'
export const gatewayConfig = defineConfig({
cache: {
type: 'redis',
host: 'localhost', // The host of the Redis server
port: 6379, // The port of the Redis server
password: undefined, // The password of the Redis server
lazyConnect: true, // If true, the connection will be established when the first operation is executed
// or
url: 'redis://localhost:6379' // The URL of the Redis server
},
responseCaching: {
session: () => null
}
})
Cloudflare Workers KV
Cloudflare Workers KV is a distributed, eventually consistent key-value store available in the Cloudflare Workers runtime. You can use Cloudflare Workers KV as a cache storage for your Hive Gateway. Learn more about KV here.
This is only available for Cloudflare Workers runtime. If you want to learn how to deploy your Hive Gateway to Cloudflare Workers, you can check the deployment documentation.
import { createGatewayRuntime } from '@graphql-hive/gateway-runtime'
import CloudflareKVCacheStorage from '@graphql-mesh/cache-cfw-kv'
import supergraph from './my-remote-supergraph-config'
export default {
fetch(request, env, ctx) {
const gateway = createGatewayRuntime({
supergraph,
transports: { http },
responseCaching: {
session: () => null
},
cache: new CloudflareKVCacheStorage({
logger,
namespace: env.NAMESPACE
})
})
ctx.waitUntil(gateway[Symbol.asyncDispose]())
return gateway(request, env, ctx)
}
}
Custom Cache Storage
You can also implement your own cache storage by extending the CacheStorage
class. It needs to
match KeyValueCache
interface from @graphql-hive/gateway
.
import { LRUCache } from 'lru-cache'
import { KeyValueCache } from '@graphql-hive/gateway'
export class MyKeyValueCache<V = any> implements KeyValueCache<V> {
// Your cache implementation here
private cache = new LRUCache<string, V>()
// Get the value of the key
async get(key: string) {
return this.cache.get(key)
}
// Set the key with the value and optional options
async set(key: string, value: V, options?: { ttl?: number }) {
this.cache.set(key, value, options?.ttl)
}
// Delete the key from the cache
async delete(key: string) {
this.cache.del(key)
}
// Get all keys that match the given prefix
async getKeysByPrefix(prefix: string) {
return Array.from(this.cache.keys()).filter(key => key.startsWith(prefix))
}
// This should be implemented if you want to clear the cache on shutdown
[Symbol.asyncDispose]() {
this.cache.reset()
}
}