I had some trouble getting Ember-CLI and Ember-Data working with my existing HTTP API. These are the things I had to do to get it working:
My API returns underscored_keys
, not camelizedKeys
. It's not exactly the standard ActiveModel, but it's quite similar. I started by defining a default (application
) serializer that's a simple subclass of DS.ActiveModelSerializer
:
// app/serializers/application.js
import DS from "ember-data";
export default DS.ActiveModelSerializer.extend({
});
One of my models -- Billing
-- has a rather funky URL: /billing/no_list=true&customer_id=:id
. To accomodate that, I defined a BillingAdapter
:
// app/billing/adapter.js (I use pods; otherwise, it would go in `app/adapters/billing.js`)
import DS from "ember-data";
export default DS.RESTAdapter.extend({
buildURL: function(type, id, record) {
return '/billing?no_list=true&customer_id=%@'.fmt(id);
}
});
Now Ember-Data is fetching my model, but it blows up when trying to populate it. Cryptically, Ember-Data tells me
Error while processing route: billing.overview Assertion Failed: Expected an object as `data` in a call to `push` for myapp@model:billing: , but was undefined
To fix this, I defined a BillingSerializer
that inserts a root billing
object in the payload:
// app/billing/serializer:
import AppSerializer from "tango/serializers/application";
export default AppSerializer.extend({
extractSingle: function(store, type, payload, id, requestType) {
return this._super(store, type, { billing: payload }, id, requestType);
}
});
Closer still! Now Ember-Data complains that the API response doesn't include an id
, which Ember-Data will need if I ever update or destroy the record. It gives me a better error message for this problem:
Error while processing route: billing.overview Assertion Failed: You must include an `id` for myapp@model:billing: in an object passed to `push`
To compensate, I added the id
in BillingSerializer#extractSingle
:
// app/billing/serializer:
import AppSerializer from "tango/serializers/application";
export default AppSerializer.extend({
extractSingle: function(store, type, payload, id, requestType) {
payload.id = id;
return this._super(store, type, { billing: payload }, id, requestType);
}
});
The /billing
API returns a deeply-nested JSON structure. I could translate those into other models and declare has-one
relationships, but really it's just structured data. No other objects in the system have references to these objects. Ember-Data doesn't have a way for me to declare these attributes, so I created an ObjectTransform
:
// app/transforms/object.js
import DS from "ember-data";
export default DS.Transform.extend({
deserialize: function(serialized) {
return serialized;
},
serialize: function(deserialized) {
return deserialized;
}
});
Then I used it in the model:
// app/billing/model.js
import DS from "ember-data";
export default DS.Model.extend({
lastBillied: DS.attr('date'),
invoice: DS.attr('object')
});