The Ferry cache normalizes incoming data for your GraphQL operations and stores it using a
Store. This allows the client to respond to future queries for the same data without sending unnecessary network requests.
Normalization involves the following steps:
- The cache generates a unique ID for every identifiable object included in the response.
- The cache stores the objects by ID in a flat lookup table.
- Whenever an incoming object is stored with the same ID as an existing object, the fields of those objects are merged.
- If the incoming object and the existing object share any fields, the incoming object overwrites the cached values for those fields.
- Fields that appear in only the existing object or only the incoming object are preserved.
Normalization constructs a partial copy of your data graph on your client, in a format that's optimized for reading and updating the graph as your application changes state.
Generating Unique Identifiers
By default, the cache generates a unique identifier using an object's
__typename and any uniquely identifying fields, called
keyFields. By default, the
_id field (whichever is defined) is used as a
keyField, but this behavior can be customized. These two values are separated by a colon (
For example, an object with a
Task and an
14 is assigned a default identifier of
Customizing Identifier Generation by Type
If one of your types defines its primary key with a field besides
_id, you can customize how the cache generates unique identifiers for that type. To do so, you define
TypePolicy for the type and include a Map of all your
typePolicies when instantiating the cache.
keyFields field in relevant
TypePolicy objects, like so:
This example shows three
typePolicies: one for a
Product type, one for a
Person type, and one for a
Book type. Each
keyFields array defines which fields on the type together represent the type's primary key.
Book type above uses a subfield as part of its primary key. The
author field must be an object that includes a
name field for this to be valid.
In the example above, the resulting identifier string for a
Book object has the following structure:
An object's primary key fields are always listed alphabetically to ensure uniqueness.
Note that these
keyFields strings always refer to the actual field names as defined in your schema, meaning the ID computation is not sensitive to field aliases.
You can instruct Ferry not to normalize objects of a certain type. This can be useful for metrics and other transient data that's identified by a timestamp and never receives updates.
To disable normalization for a type, define a
TypePolicy for the type (as shown in Customizing Identifier Generation by Type) and set the policy's
keyFields field to an empty
Objects that are not normalized are instead embedded within their parent object in the cache. You can't access these objects directly, but you can access them via their parent.
To customize how the cache interacts with specific types in your schema, you can provide an object mapping
__typename strings to
TypePolicy objects when you create a new
TypePolicy object can include the following fields:
Overriding Root Operation Types (Uncommon)
In addition to
TypePolicy can indicate that it represents the root query, mutation, or subscription type by setting
The cache normally obtains
__typename information by adding the
__typename field to every GraphQL operation selection set it sends to the server. The
__typename of the root query or mutation is almost always simply
"Mutation", so the cache assumes those common defaults unless instructed otherwise in a
The final property within
TypePolicy is the
fields property, which is a map from string field names to