Sauce Sync is a lightweight and open source BaaS that makes it easy to sync per-user data

Built on top of Google's Cloud Platform using App Engine, Cloud Endpoints, Cloud Messaging, and Cloud Datastore so that you get:
A flexible and scalable backend that you own storage

With App Engine and Cloud Datastore, you never have to worry about provisioning application or database instances. More importantly, this per-user data belongs to you, the developer, and is stored in your own Google Cloud Datastore database.

SDKs in Android, iOS, and Javascript developer_mode

Google Cloud Endpoints automatically generates Android, iOS, and Javascript libraries, making it easy to develop apps against your backend. Other clients can use the lightweight REST API.

Push notifications system_update

GCM means that iOS and Android devices sync data in real time.

OAuth2 Integration with Google account_box

Frictionless signin with Google so you don't have to worry about authentication.

Anatamy of a Sync Record

A sync record is a simple JSON document.


{
  "type" : "Task",
  "data" : {
    "localId" : "12",
    "title" : "Mow the lawn", 
    "description" : "Also, I should probably buy a lawn mower",
    "priority" : 9,
    "tags" : [
      "weekend", 
      "chores", 
      "shopping"
    ]
  },
  "deleted" : false,
  "entityId" : "DCEDFFEEFCDEF",
  "syncId": "152.1455155052639",
  "ignored" : [
    "localId"
  ],
  "indexes" : [
    "projectId",
    "priority"
  ],
  "references" : [
    {
      "arrayIndex": 0,
      "key": "projectId"
    }
  ]
}
                

type (required) - Type of the record, can be used for queries and selective sync.

data (required) - The data you want to sync. Strings, Booleans, numbers, and arrays of primites are supported.

deleted - set if the record is deleted, defaults to false. Deleted records should be removed locally, and will get reclaimed by the system in the future.

entityId - id of the sync record

ignored - Array of fields present in the "data" object that should not be persisted. Ignored fields are still returned in the "syncedEntities" array, but wont appear in other clients or subsequent syncs. Useful for passing client-only data between pre and post sync method IE an auto incrementing SQLITE id.

indexes - Array used to tell the backend which fields should be indexed. Indexed fields are usable in stand alone queries and selective sync operations. No indexes are required to perform normal sync operations.

syncId - Id that represents the sync state of the record. The system uses this to determine which objects are out of sync.

references - Used to tell the backend to inject an entityId from another record in this request into this record's data field as the provided "key". "arrayIndex" is the index of the object's entityId you want to inject. Useful when syncing two new records that dont have an entityId yet, but have some relationship, for example syncing a new Project and it's Task in one request.

The API

Sync

General purpose sync method; create, update, and delete any number of sync records at once. Provides three forms of conflict resolution (server wins, client wins, manual). Returns the records you synced and a delta of what changed since your last sync. It's also possible to 'selectively sync' records based on a type or an attribute for when you only want to remain in-sync with a subset of a user's data. The most common 'selective sync' operation is syncing based on a type.

If a client has fallen too far out of sync, a 'too far out of sync' response is returned that tells a client that they should purge their local data and re-sync.

Request
POST https://sauce-sync.appspot.com/_ah/api/sauce/v1/sync

{
  "conflictResolutionType": "MANUAL",
  "objectsToSync": 
  [
    ...any number of sync records
  ],
  "senderId": "Axcf12Edfs",
  "syncId": "152.1455155052639"
}            
              

conflictResolutionType - conflict resolution strategy, can be "MANUAL", "CLIENT_WINS", or "SERVER_WINS". Default is manual. If manual is used, when two sync operations modify the same record, the second one will get a conflict exception. A client can decide how to merge the changes, then perform a sync again.

objectsToSync - any number of sync records can be updated, created, or deleted at once

senderId - id of the client that made the request, passed as an extra by GCM in order for clients to avoid circular sync.

syncId - id that represents your sync state. Should be stored by the client and passed in on subsequent sync requests

Success Response

{
 "syncedEntities": [
    ...the records you modified
 ],
  "syncedDelta": [
    ... list of synced records that have changed since you last synced
 ],
 "syncId": "1.1455155052639"
}
              

syncedEntities - all the sync records that you created, modified, and deleted. Created records will come back with a new "entityId" and all synced records will have their "lastSyncedId" bumped up.

syncedDelta - a list of sync records that have changed since you last synced. Clients should store the updated records to remain in sync.

syncId - id that represents your sync state. Should be stored by the client and passed in on subsequent sync requests

Out of sync response
 
{
  "tooFarOutOfSyncEntities": [
    // list of sync records 
  ],
 "syncId": "1.1455155052639"
}              
              

tooFarOutOfSyncEntities - a list of sync records that need to be saved in order for the client to be 'in sync' after purging their cache of stored sync entities. This can only happen if a client has missed a sync operation for longer than a week.

syncId - id that represents your sync state once you store the out of sync records. Should be passed to subsequent sync requests

Try it out

Query

Allows a client to query for data without performing a sync operation. Useful for web apps or apps that only care about a subset of a user's data. Since Sauce Sync is built on Google Cloud Datastore, all queries must utilize an index. Only attributes marked as "indexed" may be queried.
Request
GET https://sauce-sync.appspot.com/_ah/api/sauce/v1/query
 
{
 "filters": [
  {
   "field": "priority",
   "operator": "=",
   "value": 50,
  }
 ],
 "type": "Task"
}            
              

filters - array of filters

field - field that you are filtering on, must be marked as indexed in your sync record

operator - operation for the filter, can use "=", "<=", ">=", ">", or "<"

type - Type of object you want to filter, if not set any object type that matches the filter will be returned

Try it out

Save

Lets the client create, update, or delete any number of records without performing a sync. Useful for clients that want to interact with a user's data, but dont want to grab the entire set. Commonly used with query and selective sync methods. This method is simplier than sync, and will never return a conflict, the last update will win.
Request
POST https://sauce-sync.appspot.com/_ah/api/sauce/v1/save

{
  "objectsToSave": 
  [
      // any number of sync records
  ]
}              
              

objectsToSave (required) - any number of sync records that you want to create, update, or delete.

Response

{
 "savedEntities": [
  // list of records you created, updated, and deleted
 ]
}
              

savedEntities (required) - all the objects you created, updated, or deleted in your save request. Created entities will come back with their "entityId" populated.

Try it out

Purge

Lets a client purge all of a user's data from the cloud. Only useful for when you want to remove a user from your system and start over. This method will synchronously remove all records, and reset the sync state. Normal deletes of sync records should go through the save and sync methods.
Request

DELETE https://sauce-sync.appspot.com/_ah/api/sauce/v1/purge
            
Note that this method has no body and no response. A successful purge will return a 204. Try it out

User Info

Convienece method for fetching G+ profile information. Returns email, user id, and the current sync id.
Request

GET https://sauce-sync.appspot.com/_ah/api/sauce/v1/userinfo
            
Response

{
 "userId": "113449189818224073325",
 "email": "ryanmarinaro@gmail.com",
 "syncId": "1.1455498272705",
}      
            
Try it out