To improve the response time of GET requests, JR can cache the generated JSON fragments for some or all of your Resources, using a key-based cache expiration system.
To begin, set
config.resource_cache to an ActiveSupport cache store:
JSONAPI.configure do |config|
Then, on each Resource you want to cache, call the
class PostResource < JSONAPI::Resource
The Post model in this example must have the Rails timestamp field
See the “Resources to Not Cache” section below for situations where you might not want to enable caching on particular Resources.
Also, when caching is enabled, please be careful about direct database manipulation. If you alter a database row without changing the
updated_at field, the cached entry for that resource will be inaccurate.
Instead of the default
updated_at, you can use a different field (and take on responsibility for updating it) by calling the
class Post < ActiveRecord::Base
One reason to do this is that
updated_at provides a narrow race condition window. If a resource is updated twice in the same second, it’s possible that only the first update will be cached. If you’re concerned about this, you will need to find a way to make sure your models’ cache fields change on every update, e.g. by using a unique random value or a monotonic clock.
JR does not actively clean the cache, so you must use an ActiveSupport cache that automatically expires old entries, or you will leak resources. The default behavior of Rails’ MemoryCache is good, but most other caches will have to be configured with an
:expires_in option and/or a cache-specific clearing mechanism. In a Redis configuration for example, you will need to set
maxmemory to a reasonably high size, and set
Also, sometimes you may want to manually clear the cache. If you make a code change that affects serialized representations (i.e. changing the way an attribute is shown), or if you think that there might be invalid cache entries, you can clear the cache by running
JSONAPI.configuration.resource_cache.clear from the console.
You do not have to manually clear the cache after merely adding or removing attributes on your Resource, because the field list is part of the cache key.
JSONAPI.configuration.resource_cache, you may still choose to leave some Resources uncached for various reasons:
- If your Resource is not based on ActiveRecord, e.g. it uses PORO objects or singleton resources or a different ORM/ODM backend. Caching relies on ActiveRecord features.
- If a Resource’s attributes depend on many things outside that Resource, e.g. flattened relationships, but it would be too cumbersome to have all those touch the parent resource on every change.
- If the content of attributes is affected by context in a way that is too difficult to handle with
attribute_caching_context, as described below.
If context affects the output of any method providing the actual content of an attribute, or the
fetchable_fields methods, then you must provide a class method on your Resource named
attribute_caching_context. This method should a subset of the context that is (a) serializable and (b) uniquely identifies the caching situation:
class PostResource < JSONAPI::Resource
This is necessary because cache lookups do not create instances of your Resource, and therefore cannot call instance methods like
fetchable_fields. Instead, they have to rely on finding the correct cached representation of the resource, the one generated when these methods were called with the correct context the first time. The attribute caching context is a way to let JR “sub-categorize” your cache by the various parts of your context that affect these instance methods. The same mechanism is also used internally by JR when clients request sparse fieldsets; a cached sparse representation and the cached representation with all attributes don’t collide with each other.
This becomes trickier if you depend on the state of the model, not just on the state of the context. For example, suppose you have a
UserResource#fetchable_fields that excludes
If you write a custom
ResourceSerializer which takes new options, then you must define
config_description to include those options if they might impact the serialized value:
class MySerializer < JSONAPI::ResourceSerializer