Patrick, This sounds like a cleaner approach, since you aren't "extending" the validate_doc_update responsibilities. Plus, you don't need to send an intentionally bad request to the database.
Thanks, Simeon On Thu, Mar 10, 2011 at 8:32 PM, Patrick Barnes <[email protected]> wrote: > 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<[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 >>>> >>> >> >
