Differences between revisions 9 and 10
Revision 9 as of 2013-01-23 23:11:02
Size: 3590
Editor: c-67-183-136-60
Comment: Update validate_doc_update documentation to explicitly list allowable error types
Revision 10 as of 2013-06-05 21:35:29
Size: 3731
Editor: 71
Comment: official docs link
Deletions are marked like this. Additions are marked like this.
Line 4: Line 4:

See also the [[http://docs.couchdb.org/en/latest/ddocs.html#validate-document-update-functions|official documentation]] for this topic.

We have a new wiki. The migration is not 100% complete. You can help out by moving pages across. This wiki will exist for as long as there are pages left.

The official documentation has moved to http://docs.couchdb.org — The transition is not 100% complete, but http://docs.couchdb.org should be seen as having the latest info. In some cases, the wiki still has some more or older info on certain topics inside CouchDB.

You need to be added to the ContributorsGroup to edit the wiki. But don't worry! Just email any Mailing List or grab us on IRC and let us know your user name.

Document Update Validation

See also the official documentation for this topic.

A design document may define a member function called "validate_doc_update". Requests to create or update a document are validated against every "validate_doc_update" function defined in the database. The validation functions are executed in an unspecified order. A design document can contain only one validation function. Errors are thrown as javascript objects.

Example of a design document that validates the presence of an "address" field and returns :

   1 {
   2    "_id": "_design/myview",
   3    "validate_doc_update": "function(newDoc, oldDoc, userCtx, secObj) {
   4       if (newDoc.address === undefined) {
   5          throw({forbidden: 'Document must have an address.'});
   6       }"
   7 }

The result of a document update without the address field will look like this:

HTTP/1.1 403 Forbidden
WWW-Authenticate: Basic realm="administrator"
Server: CouchDB/0.9.0 (Erlang OTP/R12B)
Date: Tue, 21 Apr 2009 00:02:32 GMT
Content-Type: text/plain;charset=utf-8
Content-Length: 57
Cache-Control: must-revalidate

{"error":"forbidden","reason":"Document must have an address."}

The "validate_doc_update" function accepts three arguments:

  1. newDoc - The document to be created or used for update.
  2. oldDoc - The current document if document id was specified in the HTTP request
  3. userCtx - User context object, which contains three properties:
    1. db - String name of database
    2. name - String user name
    3. roles - Array of roles to which user belongs. Currently only admin role is supported.
  4. secObj - The security object of the database (introduced in CouchDB-0.11.1).

Error Formats

Thrown errors must be javascript objects with a key of either "forbidden" or "unauthorized," and a value with the error message:

throw({forbidden: 'Error message here.'});


throw({unauthorized: 'Error message here.'});


Some of these functions are found in http://guide.couchdb.org/draft/validation.html . Use them inside your validate_doc_update functions.

  function required(field, message /* optional */) {
    message = message || "Document must have a " + field;
    if (!newDoc[field]) throw({forbidden : message});

  function unchanged(field) {
    if (oldDoc && toJSON(oldDoc[field]) != toJSON(newDoc[field]))
      throw({forbidden : "Field can't be changed: " + field});

  function user_is(role) {
    return userCtx.roles.indexOf(role) >= 0;

Here is a validation function I use to manage update Authorization using the roles as an ACL. A user may modify documents for which the accounts listed in his "roles" ACL are a prefix of the account specified.

  function user_match(account,message /* optional */) {
    for (var i in userCtx.roles) {
      var prefix = userCtx.roles[i];
      /* prefix-matching: "roles" will contain strings like "account:0003546" -- or define your own matching rules */
      if( ("account:"+account).substring(0,prefix.length) === prefix ) return;
    throw({forbidden : message||"No access to this account"});

  /* Usage */
  if(oldDoc) {
    if(newDoc._deleted) {
      user_match(newDoc.account,"You are not authorized to delete this document");
    } else {
      user_match(newDoc.account,"You are not authorized to modify this document");
  } else {
    user_match(newDoc.account,"You are not authorized to create this document");

Document_Update_Validation (last edited 2013-06-05 21:35:29 by 71)