Creating a Default Record When a belongsTo Request Errors
Today I had an interesting need in ember-data, which was to create an empty
record, when the API returned a 404 for a belongsTo
. Typically an
AdapterError
would be thrown, but we have some really hacky stuff in our
serializer to create a bunch of blank lines, and I basically wanted ember-data
to behave as if it had not received a 404, and return an empty record.
Note: I do not think this is necessary if you correctly follow JSONAPI, as it
should return 200 and { data: null }
.
Naturally, I reached out to runspired, and he
had an elegant solution for me, as he always does. The solution was to catch the
error in the findBelongsTo
method, and return an empty record there.
Models
The models simply setup the relationships between themselves. For the sake of illustration, we will use a person -> address relationship.
// app/models/person.js
import Model from 'ember-data/model';
import { belongsTo } from 'ember-data/relationships';
export default Model.extend({
address: belongsTo('address', { async: true })
});
// app/models/address.js
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
import { belongsTo } from 'ember-data/relationships';
export default Model.extend({
line1: attr('string'),
line2: attr('string'),
city: attr('string'),
state: attr('string'),
zip: attr('string'),
person: belongsTo('person', { async: false })
});
Adapter
The adapter is going to catch the 404, and return an object with a default value instead, so this will be serialized as the “value from the server”, and treated just like a normal server response would be.
// app/adapters/person.js
import ApplicationAdapter from './application';
export default ApplicationAdapter.extend({
async findBelongsTo(store, snapshot, url, relationship) {
const response = await this._super(
store,
snapshot,
url,
relationship
).catch((error) => {
// If the relationship is of type `address` and the error status is 404, return an empty object
if (relationship.key === 'address' && error.errors[0].status === '404') {
return {
line1: null,
line2: null,
city: null,
state: null,
zip: null
};
}
// For other errors, we should rethrow them here
throw error;
});
return response;
}
});
That’s all there is to it! It’s a pretty elegant and straightforward concept, and just one more reason ember-data is such a powerful tool.