incubator-couchdb-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Caolan McMahon <caolan.mcma...@gmail.com>
Subject Re: validate_doc_update responsibilities
Date Thu, 10 Mar 2011 08:47:18 GMT
Simeon,

If you're interested in the concept of sharing code, you might want to
take a look at Kanso (http://kansojs.org), which aims to bring all the
features of the design doc to the client-side. This means you can call
validate_doc_update on a document from the browser, or even call list,
show and update functions too. Still early days though :)

Caolan


On 10 March 2011 00:00, Simeon F. Willbanks <simeon@simeons.net> wrote:
> Justin,
>
> Thank you for the reply and helping me brainstorm a solution. I like
> the !code macro idea, but my CouchDB server isn't on the same machine
> as my application. They communicate through a network. Could I do
> this?
>
> function(newDoc, oldDoc, userCtx) {
>  //!code path/to/validate.py
>  validate(newDoc, oldDoc, userCtx);
> }
>
> path/to/validate.py would be network aware and would return valid JavaScript.
>
> Thanks,
> Simeon
>
> On Wed, Mar 9, 2011 at 1:27 PM, Justin Walgran <jwalgran@azavea.com> wrote:
>> Simeon,
>>
>> the !code macro in CouchApp was created so you can DRY up your
>> functions in the exact way you want. If you extract your validator,
>> you can include it in both your validate_doc_update function and your
>> client code. Something like this:
>>
>> function(newDoc, oldDoc, userCtx) {
>>  //!code path/to/validate.js
>>  validate(newDoc, oldDoc, userCtx);
>> }
>>
>> // Content of validate.js
>> var validate = function(newDoc, oldDoc, userCtx) {
>>        var Errors = {count: 0};
>>
>>        var Message = function(field, type, text) {
>>                this.type = type || 'string';
>>                this.text = text || field + ' is required';
>>                this.required = true;
>>        };
>>
>>        var require = function(field, type, text) {
>>                if (!newDoc[field]) {
>>                        Errors[field] = new Message(field, type, text);
>>                        Errors.count += 1;
>>                };
>>        };
>>
>>        if (newDoc.type == 'post') {
>>                require('title');
>>                require('created_at', 'datetime');
>>                require('body');
>>                require('author');
>>        };
>>
>>        if (newDoc.type == 'comment') {
>>                require('name');
>>                require('created_at', 'datetime');
>>                require('comment', 'string', 'You may not leave an empty comment');
>>        };
>>
>>        if (Errors.count > 0) {
>>                throw({forbidden: JSON.stringify(Errors)});
>>        };
>> }
>>
>> If you refactor a little further, you could go the next step and
>> generate a form from the configuration of the validator without the
>> making the extra, intentionally bad request to the server.
>>
>> Justin
>>
>>
>> On Wed, Mar 9, 2011 at 4:10 PM, Simeon F. Willbanks <simeon@simeons.net> wrote:
>>> From the 'CouchDB The Definitive Guide', "CouchDB uses the
>>> validate_doc_update function to prevent invalid or unauthorized
>>> document updates from proceeding." This clearly defines the
>>> validate_doc_update function's responsibility. That said, can we
>>> extend this responsibility a bit? I'd rather not redefine valid
>>> document attributes in my external application since
>>> validate_doc_update is already doing the work (DRY). Maybe the
>>> application can query the validate_doc_update function for the exact
>>> attributes of a valid document. Here is a proof of concept
>>> validate_doc_update function.
>>>
>>> function(newDoc, oldDoc, userCtx) {
>>>  Errors = {count: 0};
>>>
>>>  function Message(field, type, text) {
>>>    this.type = type || 'string';
>>>    this.text = text || field + ' is required';
>>>    this.required = true;
>>>  };
>>>
>>>  function require(field, type, text) {
>>>    if (!newDoc[field]) {
>>>      Errors[field] = new Message(field, type, text);
>>>      Errors.count += 1;
>>>    };
>>>  };
>>>
>>>  if (newDoc.type == 'post') {
>>>    require('title');
>>>    require('created_at', 'datetime');
>>>    require('body');
>>>    require('author');
>>>  };
>>>
>>>  if (newDoc.type == 'comment') {
>>>    require('name');
>>>    require('created_at', 'datetime');
>>>    require('comment', 'string', 'You may not leave an empty comment');
>>>  };
>>>
>>>  if (Errors.count > 0) {
>>>    throw({forbidden: JSON.stringify(Errors)});
>>>  };
>>> }
>>>
>>> In my application, before putting a new document or building a
>>> document input UI (web form), I can "query" the validate_doc_update
>>> function like so:
>>>
>>> $ curl -X PUT couchdb:5984/basic/a1a0d5f1e202b48e5bc55f616d0021ff -d
>>> '{"type":"post"}'
>>> {"error":"forbidden","reason":"{\"count\":4,\"title\":{\"type\":\"string\",\"text\":\"title
>>> is required\",\"required\":true},\"created_at\":{\"type\":\"datetime\",\"text\":\"created_at
>>> is required\",\"required\":true},\"body\":{\"type\":\"string\",\"text\":\"body
>>> is required\",\"required\":true},\"author\":{\"type\":\"string\",\"text\":\"author
>>> is required\",\"required\":true}}"}
>>>
>>> From the response, I can decode the JSON object's reason property to a
>>> useful array.
>>>
>>> array
>>>  'count' => int 4
>>>  'title' =>
>>>    array
>>>      'type' => string 'string' (length=6)
>>>      'text' => string 'title is required' (length=17)
>>>      'required' => boolean true
>>>  'created_at' =>
>>>    array
>>>      'type' => string 'datetime' (length=8)
>>>      'text' => string 'created_at is required' (length=22)
>>>      'required' => boolean true
>>>  'body' =>
>>>    array
>>>      'type' => string 'string' (length=6)
>>>      'text' => string 'body is required' (length=16)
>>>      'required' => boolean true
>>>  'author' =>
>>>    array
>>>      'type' => string 'string' (length=6)
>>>      'text' => string 'author is required' (length=18)
>>>      'required' => boolean true
>>>
>>> From this array, I can build the input UI or validate the new document
>>> before putting.
>>>
>>> To reiterate, I am trying to DRY up the validation
>>> rules/responsibilities by defining them in one spot. This proof of
>>> concept uses the validate_doc_update function in CouchDB. The
>>> validate_doc_update function is now responsible for preventing invalid
>>> documents from being PUT to CouchDB, and it can respond to application
>>> queries for what constitutes a valid document.
>>>
>>> So, is this a bad idea? Is there a more idiomatic way to accomplish this goal?
>>>
>>> Thanks,
>>> Simeon
>>>
>>
>

Mime
View raw message