incubator-couchdb-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Patrick Barnes <mrtr...@gmail.com>
Subject Re: validate_doc_update responsibilities
Date Fri, 11 Mar 2011 04:32:02 GMT
I suggest using couchapp to store your field meta-info (validation, 
format, etc) in a config/ folder or file, then you can:

a) Include it into your validate_doc_update.js file like:
function (newDoc, oldDoc, userCtx) {
// !json config.form

b) Refer to it from elsewhere like:
(PHP, because that is what I'm using)
$config = $gateway->get('_design/couchapp')->config->form;

So if you have a bunch of required fields, validation_doc_update can 
process them like:
for(field in config.form.fields) {
     ...
     if (field.required == true && !(field.name in newDoc))
	throw({forbidden:"Missing required field"});
     ...

And your application can use them like:
foreach($config->form->fields as $f) {
     ...
     $e = $form->createElement($f->type, $f->name)
	...
	->setRequired($f->required);
}

Obviously there's plenty of application-specific design work, but this 
sort of pattern allows you to store lots of validation info in a way 
that you can store it in the db (where it belongs), and still access it 
within the application.

Works for me,
-Patrick


On 10/03/2011 11:00 AM, Simeon F. Willbanks 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