Ember Data Record Links & Meta
Summary
Enable users to associate links
and meta
information with individual records
in a manner accessible via the template.
Motivation
Sometimes users have meta or links information to associate with a specific record.
Users of the json-api
specification will commonly understand this information as
belonging to an individual resource
.
While ember-data
allows for this information to exist on relationships, it does
not allow for it to exist on records, which has to this point been a glaring omission
for users of json-api
and similar specifications.
Detailed design
In keeping with the current design of the store.push
API which expects the json-api
format,
users would include optional meta
and links
information as member properties of a resource.
store.push({
data: {
type: 'contributor',
id: '1',
attributes: {},
relationships: {},
meta: {
// ... <any>
},
links: {
self: './person/1', // ... <String>
}
}
});
links
and meta
will be accepted anywhere a resource
may be encountered in a payload.
store.push({
data: [
{
type: 'contributor',
id: '1',
attributes: {},
relationships: {
projects: {
data: [
{ type: 'project', id: '1' }
]
}
},
meta: {
// ... <any>
},
links: {
self: './person/1', // ... <String>
}
}
],
included: [
{
type: 'project',
id: '1',
attributes: {},
relationships: {
contributors: {
data: [
{ type: 'contributor', id: '1' }
]
}
},
meta: {
// ... <any>
},
links: {
self: './github-projects/1', // ... <String>
}
}
]
})
Links & Meta on objects used as ResourceIdentifiers
(e.g. to link to another resource within a relationship)
will not be used for the associated resource and will be silently ignored.
let record = store.push({
data: {
type: 'contributor',
id: '1',
attributes: {},
relationships: {
projects: {
data: [
{
type: 'project',
id: '1',
meta: {}, // ignored
links: {} // ignored
}
]
}
},
}
});
Links & Meta on objects provided for Relationships
will continue to work (as they do today).
let record = store.push({
data: {
type: 'contributor',
id: '1',
attributes: {},
relationships: {
projects: {
data: [
{
type: 'project',
id: '1',
}
],
meta: {}, // available on the Record's hasMany relationship
links: {} // available on the Record's hasMany relationship
}
},
}
});
links
and meta
properties will be exposed as getters on instances of DS.Model
and will default to null
if
no meta
or links
have been provided.
let record = store.push({
data: {
type: 'person',
id: '1',
attributes: { name: '@runspired' },
meta: {
expiresDate: '2018-05-10'
},
links: {
self: './people/runspired'
}
}
});
record.meta.expiresDate; // '2018-05-10'
record.links.self; // './people/runspired'
links
and meta
will similarly be exposed as on instances of Snapshot
given to
adapter and serializer methods. In keeping with Snapshot#attributes()
, they will
be exposed as methods. Should users desire to reload a record via link, they could
achieve such by utilizing the links()
method to check for a link when making a request.
class Snapshot {
links() {}
meta() {}
}
The shared namespace problem and interop with existing workaround for links
and meta
.
The json-api
spec places type
, id
, and all members of attributes
and relationships
into
a single shared flattened namespace. This flattened namespace is what records
expose.
The spec does not put links
and meta
into this namespace, and it is valid to have links
and meta
as member names of either attributes
or relationships
.
Some apps have taken advantage of this to move links
and meta
into attributes
on their serializer
and to expose them via DS.attr
on their records.
The getter
we are proposing adding to DS.Model
would be overwriteable. In the case that there is a
conflict, the version defined by the end user model would win. It would be up to consuming apps to
decide whether they wish to avoid this conflict by renaming the non-resource links
and meta
either
in their serializer or in their API responses.
How we teach this
Documentation for DS.Model
should be updated to reflect these properties, the potential conflict
(and the default conflict resolution) explained in said documentation, and guides on working with
Models should reflect this capability.
Drawbacks
Users may sometimes encounter confusion when links
or meta
is a member of attributes or
relationships.
Alternatives
Rename
links
andmeta
to a name less likely to collide and which we fully reserve, such asrecordLinks
andrecordMeta
. We felt this would be confusing.Enforce accessing
links
andmeta
via some other object such as theReference
API. In addition to being cumbersome and confusing, this would lack discoverability and be unergonomic in templates.Enforce accessing
links
andmeta
via some imported helper, e.g.recordMetaFor(record)
orrecordLinksFor(record)
. We felt this would be confusing and unergonomic for templates.
Unresolved questions
None