decultured / ember-restless

A lightweight data persistence library for Ember.js

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Ember RESTless Build Status

RESTless is a lightweight data persistence library for Ember.js. (~3KB minified & gzipped)

Out of the box, it is used to communicate with a remote JSON REST API to map data between a server and your Ember.js application.

RESTless can be extended to support various other data persistence layers. For example, to handle XML data instead of JSON, or store data to localStorage instead of a remote server.

One of its main goals is to reproduce much of the simple, useful features of ember-data, and reflect a similar API, while remaining lightweight and stable. RESTless does not contain all of the features provided by ember-data, but was created to be less complex and contain most of the functionality needed for basic CRUD apps. Transitioning between the two should be possible with minimal effort.

Current revision: 2

See BREAKING_CHANGES for the latest API changes.

Getting started

Include ember-restless.js from the dist/ folder in your application.

Namespace

RESTless can be referenced either with the namespace RESTless or the shorthand RL. Similar to Ember and Em

Defining a 'Client'

Similar to defining the 'Store' using ember-data, instead define the 'Client' for your application. RESTless will automatically detect the Client on your application namespace. Defining a client is currently optional, and only needed if you would like to provide a custom adapter.

App.Client = RL.Client.create({
  adapter: App.RESTAdapter
});

Defining a custom RESTAdapter

Create a custom REST adapter to set the url to a backend service, and optionally a namespace.
For example, if your REST API is located at http://api.myservice.com/v1

App.RESTAdapter = RL.RESTAdapter.create({
  url: 'http://api.myservice.com',
  namespace: 'v1'
});

See the Advanced section below for further use of custom adapters.

Defining Models

Each model you create should extend RL.Model

App.User = RL.Model.extend();

Attributes

Supported types are string, number, boolean, and date. With a custom adapter, you can register custom types and transformations.

App.User = RL.Model.extend({
  name: RL.attr('string'),
  isActive: RL.attr('boolean'),
  followerCount: RL.attr('number'),
  createdAt: RL.attr('date')
});

Relationships

For one-to-one properties use the belongsTo attribute helper.

App.User = RL.Model.extend({
  profile: RL.belongsTo('App.Profile')
});
App.Profile = RL.Model.extend({
  user: RL.belongsTo('App.User')
});

One-to-many and many-to-many, use the hasMany helper.
For example, if a Post model contains an array of Tag models:

App.Tag = RL.Model.extend({
  name: RL.attr('string'),
  count: RL.attr('number')
});

App.Post = RL.Model.extend({
  tags: RL.hasMany('App.Tag')
});

Currently, all relational data should be embedded in the json response. 'Side-loading' this data may be added in a future release. For example, all of the 'tags' data should be available in the response from App.Post.find(1)

{
  "post": {
    "id": 1,
    "tags": [
      {
        "id": 1,
        "name": "tag1",
        "count": 50
      },
      {
        "id": 2,
        "name": "tag2",
        "count": 11
      }
    ]
  }
}

Finding records

To find a Post with an id of 1:

var post = App.Post.find(1);

To use a query to find:

var people = App.Person.find({ name: "Peter" });

Find all

Use find() without parameters, or alternatively, findAll()

var posts = App.Post.find();

or

var posts = App.Post.findAll();

Creating records

Create records like you would a normal Ember Object.

var post = App.Post.create({
  title: 'My First Post',
  body: 'Lorem ipsum...'
});

Saving records

To save a record call: saveRecord()
The RESTAdapter will automatically POST to save a new record, or PUT to update and existing record.

var post = App.Post.create();
post.saveRecord();

Updating:

post.set('title', 'My Very First Post');
post.saveRecord();

Deleting records

The RESTAdapter Will delete the record remotely, then destroy the object when complete:

post.deleteRecord();

'Loading' Records

You can manually populate records using raw data. For example, if you have to side-load data, you can use the load and loadMany convenience methods:

var comment = App.Comment.load(jsonData);
var tags = App.Tag.loadMany(jsonData);

Model lifecycle

RESTless supports most of the lifecycle states and events of ember-data. All model objects have the following properties added:

  • isLoaded: Record(s) have been retrieved
  • isDirty: The record has local changes that have not yet been stored
  • isSaving: Record is in the process of saving
  • isNew: Record has been created but not yet saved
  • isError: Record has been attempted to be saved, updated, or deleted but returned an error

Additionally, you can subscribe to events that are fired during the lifecycle

  • didLoad
  • didCreate
  • didUpdate
  • becameError

Event Examples:

var post = App.Post.create({
  title: 'My First Post',
  body: 'Lorem ipsum...'
});

post.on('didCreate', function() {
  console.log('post created!');
});
post.on('becameError', function(error) {
  console.log('error saving post!');
});

post.saveRecord();
var allPosts = App.Post.find();

allPosts.on('didLoad', function() {
  console.log('posts retrieved!');
});
allPosts.on('becameError', function(error) {
  console.log('error getting posts!');
});

Advanced

Custom plurals configuration

You can use a custom rest adapter to set irregular plural resource names

App.RESTAdapter.configure("plurals", {
  person: "people"
});

Changing the the primary key for a model

The primary key for all models defaults to 'id'. You can customize it per model class to match your backend:

App.RESTAdapter.map("App.Post", {
  primaryKey: "slug"
});

Mapping different property keys

For example, if your JSON has a key lastNameOfPerson and the desired attribute name is lastName:

App.Person = RL.Model.extend({
  lastName: RL.attr('string')
});
App.RESTAdapter.map('App.Person', {
  lastName: { key: 'lastNameOfPerson' }
});

Read-only attributes

Make attributes 'read-only', which will exclude them from being serialized and transmitted when saving. For example, if you want to let the backend compute the date a record is created:

App.Person = RL.Model.extend({
  firstName: RL.attr('string'),
  lastName: RL.attr('string'),
  createdAt: RL.attr('date', { readOnly: true })
});

Read-only models

If you want the entire model to be read-only and also remove all 'write' methods. Also provides a performance increase since each property won't have to be observed for 'isDirty'.

App.Post = RL.ReadOnlyModel.extend({
...
});

Custom transforms

You can use a custom rest adapter to add custom transforms:

App.RESTAdapter.registerTransform('timeAgo', {
  deserialize: function(serialized) {
    // return a custom date string, such as: '5 minutes ago'
  },
  serialize: function(deserialized) {
    // return a custom date json format for your backend or 
    // simply return deserialized
  }
});
App.Comment = RL.Model.extend({
  createdAt: RL.attr('timeAgo')
});

Custom Adapters & Serializers

RESTless is abstracted so you can write your own Adapters and Serializers.

App.XMLSerializer = RL.Serializer.create({
  ...
});
App.SOAPAdapter = RL.Adapter.create({
  serializer: App.XMLSerializer
  ...
});
App.Client = RL.Client.create({
  adapter: App.SOAPAdapter
});

Building RESTless

If you wish to build ember-restless yourself, you will need node.js and Grunt.

  1. Install node: http://nodejs.org/
  2. Open a terminal window
  3. Install dependencies: npm install
  4. Build: grunt
  5. Output will be dist/ember-restless.js and dist/ember-restless.min.js

Tests

Uses QUnit.
Tests are run during the grunt build process.
To run tests manually, you can open tests/index.html in a browser.
Tests are currently a work in progress.

Example App

Coming soon.

Contributors

Thanks to the Ember core team and contributors for creating Ember and Ember Data.
Special thanks to the following for creating & contributing to the ember-restless project:

About

A lightweight data persistence library for Ember.js

License:MIT License