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 <[email protected]> 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 <[email protected]>
> 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
>>
>