-
Notifications
You must be signed in to change notification settings - Fork 138
Sync Function API
The sync function is the core API you'll be interacting with on the Sync Gateway. For simple applications it may be the only server-side code you need to write. For more complex applications it will still be a primary touch point for managing data routing and access control.
Learn about channels and user authentication here and read this page for a detailed example.
If you don't supply a sync function we'll use this as a default:
function (doc) {
channel(doc.channels);
}
The sync function has three arguments, which allow it to be used for validation as well as data routing.
function (doc, oldDoc, userCtx) {
// your code here
}
-
doc
The first argument is the document that is being saved. This will match the JSON that was saved by the mobile client and replicated to Sync Gateway. There are no metadata or other fields added, although the
_id
and_rev
fields are available. -
oldDoc
If the document has been saved before, the revision that is being replaced will be available here. In the case of a document with conflicting revision, the provisional winning revision will be passed as the
oldDoc
parameter. Read more about Conflict Detection and Mangement. -
userCtx
This is an object that contains details about the currently authenticated user. It has these fields:
-
name
This is the name of the user, which will be unique across the database, and which should not change over time. A common use for this field is to ensure that a field like
doc.author
is the same asuserCtx.name
so that it's not possible to impersonate another user by writing a document which lists someone else as the author. If the user is not authenticated, the name field will contain""
-- an empty string. -
roles
This field is an array of strings which the administrator can associate with a user. So for instance you can add the role
"manager"
to some of your users, and then grant access to some channels to all managers without having to grant it to all of them individually. In general granting channel access to roles instead of individual users will result in Sync Gateway maintaining more parsimonious internal data structures, giving improved performance. The reasonroles
is available here, is so you can also use role membership to control what kind of documents a user can write. -
channels
This field allows you to peek at the channels a given user can read from. Because the sync function determines which channels a document lands in, it can also prevent the user from writing to channels they can't access (if you choose.) Note that by default a user can write to any channel, even those they can't read.
-
From within the sync function you create changes in the Sync Gateway configuration via callback functions. Each call manages a small amount of configuration state. It is also tied back to the document which initiated the call, so that when the document is modified, any configuration made by an old version of the document is replaced with configuration derived from the newer version. Via these APIs, documents are mapped to channels. They can also grant access to channels, either to users or roles. Finally, you can reject an update completely by throwing an error. The error message will be returned to the synchronizing client, which will log it or potentially display it to the user.
The sync function can prevent a document from persisting or syncing to any other users by calling throw()
with an error object. This also prevents the document from changing any other gateway configation. Here is an example sync function which disallows all writes to the database it is in.
function (doc) {
throw({forbidden : "read only!"})
}
The error object may be either a forbidden
error (corresponding to an HTTP 403 error code) or an unauthorized
error (corresponding to HTTP 401 error). The forbidden
error should be used if the user is already authenticated, and they account they are syncing with is not permitted to modify or create the document. The unauthorized
error should be used if the account is not authenticated. Some user agents will trigger a login workflow when presented with a 401 error.
A quick rule of thumb: most of the time you should use the throw({forbidden : "your message here"})
as most applications will require users to be authenticated before any reads or writes can occur.
The channel
call routes the document to the named channel. It accepts either a string channel name, or an array of strings, if the document should be added to multiple channels in a single call. The channel function can me called zero or more times from the sync function, for any document. The default function (listed at the top of this document) routes documents to the channels listed on them. Here is an example that routes all "published" documents to the "public" channel, and all "unpublished" documents to a drafts channel specific to the channel author.
function (doc, oldDoc, userCtx) {
if (doc.published) {
channel("public");
} else {
channel("drafts-" + userCtx.name);
}
}
The access
call grants access to channel to a given user or list of users. It can be called multiple times from a sync function. If the document that granted access is deleted, the access is revoked. Note that revoking access to a channel will not delete the documents which have already been synced to a user's device.
The access call takes two arguments, the user (or users) and the channel (or channels). These are all valid ways to call it:
access("jchris", "mtv")
access("jchris", ["mtv", "mtv2", "vh1"])
access(["snej", "jchris"], "vh1")
access(["snej", "jchris"], ["mtv", "mtv2", "vh1"])
Here is an example function which grants access to a channel for all the user's listed on a document:
function (doc, oldDoc, userCtx) {
if (doc.members && doc.channel_name) {
access(doc.members, doc.channel_name);
}
// we should also put this document on the channel it manages
channel(doc.channel_name)
}
TODO: this is not yet implemented
TODO: this is not yet implemented
The best resource to see a full example is the Chat App Data Model article.