Cache API
There are times where Houdini’s automatic cache updates or list operation fragments are not sufficient. For those times, Houdini provides a programatic API for interacting with the cache directly. If you find yourself relying on this API for a considerable amount of your business logic, please open an issue or discussion on GitHub so we can try to figure out if there is something that Houdini could be doing better. This should be considered an advanced escape hatch for one-off situations.
Enabling the API
This API is currently considered experimental and while we refine it, we might need to dramatically change it overall shape. Until it’s ready, we want to reserve the ability to break its API on any minor version. We understand this is not technically semantic versioning but ultimately it will let us refine the API against real applications and lead to a better solution faster.
In order to acknowlege this, you will need to enable the acceptImperativeInstability
flag in your config file:
export default {
// ...
acceptImperativeInstability: true
}
Records
The primary unit of the cache api is the Record
. It acts as a proxy for interacting with entities in Houdini’s cache
and does not actually hold onto any values. Retrieving a record from your cache is done
with the get
method on the cache
exported from $houdini
:
import { cache } from '$houdini'
const user = cache.get('User', { id: "1" })
Once you have the reference, you can retrieve values using the get
method on the record:
const user = cache.get('User', { id: "1" })
// scalar values can be retrieved, custom scalars will be marshaled
const fullName = user.get({ field: "fullName" })
// links to other records can also be retrieved
const bestFriend = user.get({ field: "bestFriend" })
// if you need to retrieve the value when specific arguments are
// set, you should use the args parameter
const formattedName = user.get({
field: "fullName",
args: {
format: "FIRST_LAST"
}
})
You can also update values using the set
method. Keep in mind that when you set a value
that points to a linked record, you need to set it to another instance of Record
:
const user = cache.get('User', { id: "1" })
// scalar values will be marshaled appropriately
user.set({ field: "fullName", value: "Houdini" })
// when setting linked records, you need to pass another record
user.set({
field: "bestFriend",
value: cache.get('User', { id: "3" })
})
// as with get, you can pass arguments to the field
user.set({
field: "fullName",
value: "HOUDINI_GRAPHQL",
args: {
format: "FIRST_LAST"
}
})
You can also delete a record from the cache using the delete
method:
const user = cache.get('User', { id: "1" })
user.delete()
Field schema information
There are a few situations where the runtime might complain that it doesn’t know the type of the field that you have set.
For example, if you are setting a field that has not yet been queried. When this happens, you will need
to provide some additional information so we can ensure that your responses are always valid.
To do this, use cache.setFieldType
:
cache.setFieldType({
parent: 'User',
key: 'fullName',
type: 'String',
nullable: false,
})
// links to other records must have `link` set to true
cache.setFieldType({
parent: 'User',
key: 'bestFriend',
type: 'User',
nullable: true,
link: true
})
Lists
Another primitive provided by the cache
instance is List
and it provide a programatic
API for the same operations supported by the list operation fragments.
Accessing a list can be done with the list
method:
const allUsers = cache.list("All_Users")
const userFriends = cache.list("User_Friends", { parentID: "1" })
const allFriends = cache.list("User_Friends", { allLists: true })
You can mutate the list using the prepend
, append
, remove
, and toggle
methods:
const allUsers = cache.list("All_Users")
const user1 = cache.get('User', { id: "1" })
// add it to the beginning
allUsers.prepend(user1)
// add it to the end
allFriends.append(user1)
// remove it from the list
allFriends.remove(user1)
// if its in list, remove it. Otherwise, add it to the front.
// You can also also pass 'last' to insert it to the end of the list
allFriends.toggle('first', user1)
If you only want to operate on the list depending on argument values, you can use the when
method
allFriends.when({ favorites: true }).append(user1)