Slide 1

Slide 1 text

Optimizing An API For Ember Data Dan Gebhardt Saturday, February 16, 13

Slide 2

Slide 2 text

Dan Gebhardt @dgeb Saturday, February 16, 13

Slide 3

Slide 3 text

Convention Configuration Saturday, February 16, 13

Slide 4

Slide 4 text

“Trivial choices are the enemy” - Yehuda Katz Saturday, February 16, 13

Slide 5

Slide 5 text

Ruby on Rails ActiveModel::Serializers Ember.js Ember Data Saturday, February 16, 13

Slide 6

Slide 6 text

Saturday, February 16, 13

Slide 7

Slide 7 text

“What” not “how” DRY Customizable ActiveModel::Serializers Saturday, February 16, 13

Slide 8

Slide 8 text

Ember Data In memory store Canonical records Multi-layered architecture Customizable adapters / serializers Saturday, February 16, 13

Slide 9

Slide 9 text

underscore_naming include root element id: 1, fk_id: 1, fk_ids: [1] conventions for including related data AM::S Conventions Saturday, February 16, 13

Slide 10

Slide 10 text

DS.RESTAdapter Conventions underscore_naming include root element id: 1, fk_id: 1, fk_ids: [1] conventions for including related data Saturday, February 16, 13

Slide 11

Slide 11 text

DS.RESTAdapter Conventions underscore_naming include root element id: 1, fk_id: 1, fk_ids: [1] conventions for including related data IDENTICAL TO ActiveModel::Serializers Saturday, February 16, 13

Slide 12

Slide 12 text

class ApplicationSerializer < ActiveModel::Serializer # sideload related data by default embed :ids, include: true end A Sprinkling of Configuration Saturday, February 16, 13

Slide 13

Slide 13 text

Relationships source: twitamore.com Saturday, February 16, 13

Slide 14

Slide 14 text

One-to-Many Relationships App.Post = DS.Model.extend({ title: DS.attr('string'), comments: DS.hasMany('App.Comment') }); App.Comment = DS.Model.extend({ body: DS.attr('string'), post: DS.belongsTo('App.Post') }); Saturday, February 16, 13

Slide 15

Slide 15 text

class PostSerializer < ApplicationSerializer attributes :title has_many :comments end class CommentSerializer < ApplicationSerializer attributes :body belongs_to :post end One-to-Many Relationships Saturday, February 16, 13

Slide 16

Slide 16 text

{ post: { id: 1, title: 'Ember is Omakase', comment_ids: [4, 5, 6] }, comments: [ {id: 4, post_id: 1, body: 'delicious!'}, {id: 5, post_id: 1, body: 'yuno turbolinks?'}, {id: 6, post_id: 1, body: 'is that a tentacle?'} ] } JSON One-to-Many Relationships Saturday, February 16, 13

Slide 17

Slide 17 text

One-to-One Relationships App.User = DS.Model.extend({ name: DS.attr('string'), rights: DS.belongsTo('App.Rights') }); App.Rights = DS.Model.extend({ admin: DS.attr('boolean'), user: DS.belongsTo('App.User') }); Saturday, February 16, 13

Slide 18

Slide 18 text

class UserSerializer < ApplicationSerializer attributes :id, :name has_one :rights end class RightsSerializer < ApplicationSerializer attributes :id, :admin belongs_to :user end One-to-One Relationships Saturday, February 16, 13

Slide 19

Slide 19 text

{ user: { id: 1, name: '', rights_id: 2 }, rights: [{ id: 2, admin: true, user_id: 1 }] } JSON One-to-One Relationships Saturday, February 16, 13

Slide 20

Slide 20 text

One-to-None Relationships App.User = DS.Model.extend({ name: DS.attr('string'), rights: DS.belongsTo('App.Rights') }); App.Rights = DS.Model.extend({ admin: DS.attr('boolean') }); Saturday, February 16, 13

Slide 21

Slide 21 text

class UserSerializer < ApplicationSerializer attributes :id, :name has_one :rights end class RightsSerializer < ApplicationSerializer attributes :id, :admin end One-to-None Relationships Saturday, February 16, 13

Slide 22

Slide 22 text

{ user: { id: 1, name: '', rights_id: 2 }, rights: [{ id: 2, admin: true }] } JSON One-to-None Relationships Saturday, February 16, 13

Slide 23

Slide 23 text

Many-to-Many Relationships App.Post = DS.Model.extend({ title: DS.attr('string'), body: DS.attr('string'), tags: DS.hasMany('App.Tag') }); App.Tag = DS.Model.extend({ name: DS.attr('string'), posts: DS.hasMany('App.Post') }); Saturday, February 16, 13

Slide 24

Slide 24 text

class PostSerializer < ApplicationSerializer attributes :id, :title, :body has_many :tags end class TagSerializer < ApplicationSerializer attributes :id, :name has_many :posts end Many-to-Many Relationships Saturday, February 16, 13

Slide 25

Slide 25 text

{ posts: [ {id: 1, title: 'Hello world', tag_ids: [11, 12]}, {id: 2, title: 'Goodbye', tag_ids: [11, 13]} ], tags: [ {id: 11, name: 'announcements', post_ids: [1,2]}, {id: 12, name: 'happy', post_ids: [1]}, {id: 13, name: 'sad', post_ids: [2]} ] } JSON Many-to-Many Relationships Saturday, February 16, 13

Slide 26

Slide 26 text

Many-to-None Relationships App.Post = DS.Model.extend({ title: DS.attr('string'), body: DS.attr('string'), tags: DS.hasMany('App.Tag') }); App.Tag = DS.Model.extend({ name: DS.attr('string') }); Saturday, February 16, 13

Slide 27

Slide 27 text

class PostSerializer < ApplicationSerializer attributes :id, :title, :body has_many :tags end class TagSerializer < ApplicationSerializer attributes :id, :name end Many-to-None Relationships Saturday, February 16, 13

Slide 28

Slide 28 text

{ posts: [ {id: 1, title: 'Hello world', tag_ids: [11, 12]}, {id: 2, title: 'Goodbye', tag_ids: [11, 13]} ], tags: [ {id: 11, name: 'announcements'}, {id: 12, name: 'happy'}, {id: 13, name: 'sad'} ] } JSON Many-to-None Relationships Saturday, February 16, 13

Slide 29

Slide 29 text

Embedded Relationships Creative Commons licensed by: Subhash Chandra Saturday, February 16, 13

Slide 30

Slide 30 text

{ post: { id: 1, title: 'Ember is Omakase', comments: [ {id: 4, body: 'delicious!'}, {id: 5, body: 'yuno turbolinks?'}, {id: 6, body: 'is that a tentacle?'} ] } } JSON Serialized Embedded Data Saturday, February 16, 13

Slide 31

Slide 31 text

class PostSerializer < ApplicationSerializer attributes :title has_many :comments, embed: :objects end class CommentSerializer < ApplicationSerializer attributes :body belongs_to :post end Embedded Data Serializers Saturday, February 16, 13

Slide 32

Slide 32 text

Embedded Read-only Data App.Post = DS.Model.extend({ title: DS.attr('string'), comments: DS.hasMany('App.Comment') }); App.Comment = DS.Model.extend({ body: DS.attr('string') }); serializer.map('App.Post', { comments: {embedded: 'load'} }); Saturday, February 16, 13

Slide 33

Slide 33 text

Embedded Writeable Data App.Post = DS.Model.extend({ title: DS.attr('string'), comments: DS.hasMany('App.Comment') }); App.Comment = DS.Model.extend({ body: DS.attr('string') }); serializer.map('App.Post', { comments: {embedded: 'always'} }); Saturday, February 16, 13

Slide 34

Slide 34 text

Customizations Saturday, February 16, 13

Slide 35

Slide 35 text

{ hobbit: {id: 1, name: 'Bilbo'} } { hobbitses: [ {id: 1, name: 'Bilbo'} {id: 2, name: 'Frodo'} {id: 3, name: 'Samwise'} ] } JSON Custom Pluralization Saturday, February 16, 13

Slide 36

Slide 36 text

Custom Pluralization serializer.configure('plurals', { hobbit: 'hobbitses' }); Saturday, February 16, 13

Slide 37

Slide 37 text

{ post: { id: 1, titleOfPost: 'Ember is Omakase' } } JSON Custom Keys Saturday, February 16, 13

Slide 38

Slide 38 text

Custom Keys serializer.map('App.Post', { title: {key: 'titleOfPost'} }); Saturday, February 16, 13

Slide 39

Slide 39 text

{ post: { id: 1, title: 'Ember is Omakase', comment_ids: [4, 5, 6] }, post_comments: [ {id: 4, post_id: 1, body: 'delicious!'}, {id: 5, post_id: 1, body: 'yuno turbolinks?'}, {id: 6, post_id: 1, body: 'is that a tentacle?'} ] } JSON Custom Sideloading Saturday, February 16, 13

Slide 40

Slide 40 text

Custom Sideloading serializer.configure('App.Comment', { sideloadAs: 'post_comments' }); Saturday, February 16, 13

Slide 41

Slide 41 text

Custom Transforms Adapter.registerTransform('excitableString', { serialize: function(value) { return value + '!'; }, deserialize: function(value) { return value.substring(0, value.length - 1); } }); App.Greeting = DS.Model.extend({ message: DS.attr('excitableString') }); Saturday, February 16, 13

Slide 42

Slide 42 text

Custom URLs adapter.set('namespace', 'ember'); person = store.find(Person, 1); // => /ember/people/1 adapter.set('url', 'http://api.ember.dev'); person = store.find(Person, 1); // => http://api.ember.dev/people/1 Saturday, February 16, 13

Slide 43

Slide 43 text

Bulk Commits adapter.set('bulkCommit', true); store.createRecord(App.Person, {name: 'tomdale'}); store.createRecord(App.Person, {name: 'wycats'}); store.commit(); // POST to /people // {people: [{name: 'tomdale'}, {name: 'wycats'}]} Saturday, February 16, 13

Slide 44

Slide 44 text

Edge of Convention Pagination Authentication Sparse fieldsets Custom includes Polymorphism Creative Commons licensed by: _chrisUK Saturday, February 16, 13

Slide 45

Slide 45 text

Resources https://github.com/dgeb/ember_data_example https://github.com/rails-api/active_model_serializers http://stackoverflow.com/questions/tagged/ember-data Saturday, February 16, 13