I've done quick write-up on the now-completed {.format} thing here
(with a clarifying comment or two) :
 * http://positiveincline.com/?p=617

This gist has the refactored and json-capable @validate plus other
small goodies referred to in previous discussions:
 * http://gist.github.com/301613

Usage:

A typical json-capable GET action ends with something like this:

        if accepts_json():
            return render_json(thing.to_dict()) # to_dict is
implemented in my model
        else:
            return render(template)

[When rendering forms, render() is replaced by fill_render() - see
previous discussions on repeating groups.  Maybe I should consolidate
them into one.]

Create and update actions end with

        return redirect_to(formatted_url(...))

which remembers any format extension on the request.  I'm tempted to
import formatted_url as url but I haven't yet.

As I'm already relying on the latest SubMapper helpers (I never use
resource() and hardly use connect()), the {.format} extensions came by
default and my confg/routing.py needed very little change.  To be on
the safe side I added requirements=dict(format='json') at SubMapper/
collection level (a handful of places in my case).  To minimise this,
maybe there needs to be a single place where a default pattern (or
even requirements in general?) can be registered.  Thinking about it,
an outer SubMapper might do the trick...

It's not quite as generic as it might be, since we have helpers like
accepts_json() rather than accepts('json'), but it's easy to use and
good enough for my purposes.  To generalise it, mappings between
format names and MIME types would be needed.

Clients can request json by adding either a .json path extension or an
accept:application/json header (the extension takes precedence).
Successful PUT/POST actions (client payload type having been
determined by extension or content-type header) return a redirect to
the created or updated resource, carrying forward the extension if
there was one.  Validation failures are returned in a 200 OK response
with the expected content-type; if json, the body contains '{"errors":
form_errors}'.

So...  anyone else interested?

Regards,
Mike


On Feb 9, 2:58 pm, Mike Burrows <[email protected]> wrote:
> Hi,
>
> No, not another whinge - maybe there's life in @validate yet!
>
> Locally to my project, I have a refactored @validate decorator sitting
> in my lib/base.py, with most of the work of what was previously a 100+
> line function extracted to methods on BaseController.  What's left of
> the function lis shown at the end of this message - the extracted
> methods are obvious enough if you have seen the original function.
>
> The JSON twist:  The new _get_decoded() method adds the ability to
> handle request bodies sent in JSON, and the new
> _handle_validation_errors() method will render errors in JSON if
> that's the format the client wants to accept.  Just a couple of lines
> in each case.
>
> In my controllers, "show" and "list" actions needed a small change to
> render JSON if requested, but the create and update actions needed no
> change at all.  Model objects all gained a to_dict() method, used by
> the controllers to provide input to the json rendering.  In the
> objects I most care about, the dict representation was tweaked a
> little by hand.  Very modest effort for a basic JSON API I think.
>
> This new @validate is clearly more extensible than the old one but I
> still wonder about the extension interface.  For example, does the
> request parsing bit (especially the JSON part) belong here, in (say)
> an extensible or otherwise format-aware request object, or somewhere
> else - a new validation or form object, say?
>
> While we're here, I'm thinking of a Routes enhancement (in the form of
> a personal extension if no-one else likes the idea) that allows a
> {.format} syntax - already proposed to the URI Template people - as a
> parameter style for optional format extensions.  The removal of large
> numbers of "formatted routes" might even yield a small performance
> benefit for some people, but even if it doesn't, I for one will be
> pleased to help see some duplication disappear.  Meanwhile I have only
> header-based conneg, which gets a bit tedious at times!
>
> Finally, I would like a more sophisticated conneg function than my
> current accepts_json(request), but before I start to write one, surely
> such things exist already?
>
> Regards,
> Mike
> [email protected]http://positiveincline.comhttp://twitter.com/asplake
>
> def validate(schema=None, validators=None, form=None,
> variable_decode=False,
>              dict_char='.', list_char='-', post_only=True, state=None,
>              on_get=False, **htmlfill_kwargs):
>     """The Pylons @validate decorator refactored, with most of the
> work done
>     by controller methods defined on BaseController.  Enhanced to
> accept JSON.
>     """
>     if state is None:
>         state = PylonsFormEncodeState
>     def wrapper(func, self, *args, **kwargs):
>         """Decorator Wrapper function"""
>         request = self._py_object.request
>
>         # Skip the validation if on_get is False and its a GET
>         if not on_get and request.environ['REQUEST_METHOD'] == 'GET':
>             return func(self, *args, **kwargs)
>
>         decoded = self._get_decoded(
>                                 variable_decode, dict_char, list_char,
>                                 post_only)
>         self.form_result, self.form_errors = self._convert(
>                                 decoded, schema, validators, state,
>                                 variable_decode, dict_char, list_char)
>         if self.form_errors:
>             return self._handle_validation_errors(func, decoded,
>                                                   self.form_errors,
> form,
>                                                   htmlfill_kwargs,
>                                                   args, kwargs)
>         else:
>             return func(self, *args, **kwargs)
>     return decorator(wrapper)

-- 
You received this message because you are subscribed to the Google Groups 
"pylons-discuss" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.

Reply via email to