Customizing Ember Data

Kyle Coberly

www.kylecoberly.com

Adapters

Where should data requests be sent?

Serializers

How does the data need to be formatted?

Ember Data

Included:

Adapter

JSONAdapter

RESTAdapter

JSONAPIAdapter

Included:

Serializer

JSONSerializer

RESTSerializer

JSONAPISerializer

Creating Adapters

An application adapter applies to every request in the application

ember g adapter application
ember g adapter some-model

An model-specific adapter applies to every request for one particular model

Creating Serializers

Same thing applies to serializers

ember g serializer application
ember g serializer some-model

JSON API

{
    "links": {
        "next": "http://example.com/articles?page[offset]=2"
    },
    "data": [{
        "type": "articles",
        "id": "1",
        "attributes": {
            "title": "JSON API paints my bikeshed!",
            "date": "2/18/15"
        },
        "relationships": {
            "author": {
                //another JSON API document
            }
        },
        "links": {
            "self": "http://example.com/articles/1"
        }
    }],
    "included": [{
        //sideloaded data
    }]
}
  • New recommended data format for APIs
  • Used internally in Ember Data

Adapter Methods

  • Determines where store requests go
  • Adapters should override the DS.Adapter class
  • Write some kind of implementation for each
this.store.findRecord();
this.store.createRecord();
this.store.updateRecord();
this.store.deleteRecord();
this.store.findAll();
this.store.query();
this.store.findMany();

Writing an Adapter

The store proxies the request to the adapter

import DS from "ember-data";

export default DS.Adapter.extend({
    findAll(store, type){
        let query = {
            sort: "ascending"
        };

        return this.ajax(this.buildURL(type.typeKey), "GET", {
            data: query
        });
    }
});
import Ember from "ember";

export default Ember.Route.extend({
    model(){
        return this.store.findAll("someModel");
    }
});

Overriding RESTAdapter Properties

  • Can be done at the application level
  • Can be overridden for each model
  • Requests will start with to http://www.kylecoberly.com/api
  • Headers are sent on every request
import DS from 'ember-data';

export default DS.RESTAdapter.extend({
    host: "kylecoberly.com",
    namespace: "api",
    headers: { //Could also be a computed property
        headerName: "Header Value",
        computedHeader: function(){
            return "A computed value";
        }
    }
});

Overriding buildURL

  • Can be done at the application level
  • Can be overridden for each model
  • Requests for "conversations" will go to http://www.kylecoberly.com/me/convos
  • this._super() runs the original function
  • Otherwise, build it yourself from host and namespace
import DS from 'ember-data';

export default DS.RESTAdapter.extend({
    buildURL(model, id, snapshot, requestType, query) {
        let url = this._super(); //old URL

        if (url.toString().contains('conversations')){
            url = url.replace('conversations', 'me/convos');
        } //new URL

        return url;
    }
});

Using serialize()

  • Transforms data from the server to the data your Ember app expects
  • this.serialize() proxies the request to the related serializer
  • Application Adapter will use the Application Serializer, etc.
import DS from 'ember-data';

export default DS.RESTAdapter.extend({
    createRecord(model, id, snapshot, requestType, query) {
        let data = this.serialize(snapshot);
        return this.ajax(this.buildURL(type.typeKey), "POST", data);
    }
});

Serializer Methods

  • Translate from Ember to API and back again
  • Serialize to format Ember data for the API
  • Normalize to format for Response data for Ember
  • Serializer doesn't have to match Adapter (eg. RESTAdapter with ActiveModelSerializer)
this.normalize();
this.serialize();

Writing a Serializer

  • Can be application-wide or model specific
import DS from "ember-data";

export default DS.Serializer.extend({
    serialize(snapshot, options){
        return JSON.stringify({
            title: snapshot.attr("title"),
            author: snapshot.attr("author")
        });
    },
    normalize(modelName, dataHash){
        return {
            data: {
                id: dataHash.id,
                title: dataHash.title,
                author: dataHash.author
            }
        };
    }
});

Overriding RESTSerializer Properties

  • primaryKey will map its value to "id" in Ember
  • attrs will map other properties
import DS from "ember-data";

export default DS.RESTSerializer.extend({
    primaryKey: "_id",
    attrs: {
        emberName: "serverName",
        otherEmberName: {
            key: "otherServerName"
        },
        willNotBeSerialized: {
            serialize: false
        }
    }
});

Overriding RESTSerializer Methods

  • Each one starts with "normalize", ends in "Response"
  • Each one maps to its store action
  • Each one has the same interface
import DS from "ember-data";

export default DS.RESTSerializer.extend({
    normalizeFindAllResponse(store, primaryModelClass, payload, id, requestType){
        return {
            data: {
                id: payload.id,
                title: payload.title,
                author: payload.author
            }
        };
    }
});

RESTAdapter Normalize Methods

  • normalizeResponse()

  • normalizeFindAllResponse()

  • normalizeFindRecordResponse()

  • normalizeFindManyResponse()

  • normalizeFindBelongsToResponse()

  • normalizeFindHasManyResponse()

  • normalizeQueryResponse()

  • normalizeQueryRecordResponse()

  • normalizeCreateRecordResponse()

  • normalizeDeleteRecordResponse()

  • normalizeUpdateRecordResponse()

  • normalizeSaveResponse()

  • normalizeSingleResponse()

  • normalizeArrayResponse()

Other RESTSerializer Methods

  • serializeAttribute()
  • serializeBelongsTo()
  • serializeHasMany()

Questions?

Thank You!

www.kylecoberly.com

Customizing Ember Data

By Kyle Coberly

Customizing Ember Data

Presentation to Denver Ember on customizing Ember Data

  • 534
Loading comments...

More from Kyle Coberly