ResourceSchemas
ResourceSchemas define the top level resources in your data layer.
They describe your application’s data structure in one place, including fields, relationships and embedded objects, without hidden magic.
A ResourceSchema is the backbone of how WarpDrive understands your data.
A ResourceSchema has a "mode" which instructs WarpDrive on how a ReactiveResource should behave. There are currently two modes:
Why ResourceSchemas Matter
ResourceSchemas give you clarity by making every field and relationship explicit. They provide consistency because the schema drives the cache, transforms and UI bindings. They bring reactivity so changes anywhere in a resource flow through to your app automatically. They also work across any JavaScript environment including Ember, React or a Node process without a DOM.
Creating a ResourceSchema
The easiest way to create a ResourceSchema is to use withDefaults. This sets up sensible defaults such as the primary key.
import { withDefaults } from '@warp-drive/core/reactive';
export const UserSchema = withDefaults({
type: 'user',
fields: [
{ name: 'firstName', kind: 'field' },
{ name: 'lastName', kind: 'field' },
{ name: 'email', kind: 'field' },
{ name: 'team', kind: 'resource', type: 'team' }
]
});Key Points
The type identifies the resource (the ResourceType).fields describes each piece of data:
fieldfor primitive dataresourcefor a single related resourcecollectionfor multiple related resourcesschema-objectfor an embedded object schema
withDefaults automatically provides an identity field of { name: 'id', kind: '@id' } unless you override it.
Registering a ResourceSchema
Once defined, register your schema with the store so WarpDrive can use it at runtime.
store.schema.registerResource({
type: 'user',
identity: { kind: '@id', name: 'id' },
fields: [
{ kind: 'field', name: 'firstName', sourceKey: 'first_name' },
{ kind: 'field', name: 'lastName', sourceKey: 'last_name' },
{ kind: 'field', name: 'lastSeen', sourceKey: 'last_seen', type: 'date-time' },
{
kind: 'resource',
name: 'bestFriend',
sourceKey: 'best-friend',
options: { async: false, inverse: null }
},
{
kind: 'collection',
name: 'pets',
options: { async: false, inverse: null, polymorphic: true }
},
]
});identity→ defines the primary keysourceKey→ maps API field names to local names (first_name→firstName)resourceandcollection→ relationships to other schemas (belongsTo / hasMany)typeon a field → plugs in transforms for dates, URLs, decimals, etc.
After registering you can fetch or create data for that resource:
const user = await store.request(findRecord('user', '1'));
console.log(user.firstName);Common Field Kinds
| Kind | Purpose |
|---|---|
field | Basic data (string, number, boolean) |
resource | One related record (similar to a belongs-to) |
collection | Multiple related records (similar to a has-many) |
schema-object | Embedded object schema with no top level identity |
By defining your data with ResourceSchemas, you create a clear contract between your API, your cache and your UI. This makes your application more maintainable, predictable and ready for the future.