JSON and validation

Introduction

Morepath lets you define a JSON representations for arbitrary Python objects. When you return such an object from a json view, the object is automatically converted to JSON.

When JSON comes in as the POST or PUT body of the request, you can define how it is to be converted to a Python object and how it is to be validated.

This feature lets you plug in external (de)serialization libraries, such as Marshmallow. We’ve provided Marshmallow integration for Morepath in more.marshmallow

dump_json

The morepath.App.dump_json() directive lets you define a function that turns a model of a particular class into JSON. Here we define it for an Item class:

class Item(object):
   def __init__(self, value):
       self.value = value

@App.dump_json(model=Item)
def dump_item_json(self, request):
    return { 'type': 'Item', 'x': self.value }

So for instance, Item('foo') is represented in JSON as:

{
  'type': 'Item',
  'x': 'foo'
}

If we omit the model argument from the directive, we define a general dump_json function that applies to all objects.

Now we can write a JSON view that just returns an Item instance:

@App.json(model=Item)
def item_default(self, request):
    return self

The self we return in this view is an istance of Item. This is now automatically converted to a JSON object.

load function for views

When you specify the load function in a view directive you can specify how to turn the request body for a POST or PUT method into a Python object for that view. This Python object comes in as the third argument to your view function:

def my_load(request):
    return request.json

@App.json(model=Item, request_method='POST', load=my_load)
def item_post(self, request, obj):
   # the third obj argument contains the result of my_load(request)

The load function takes the request and must return some Python object (such as a simple dict). If the data supplied in the request body is incorrect and cannot be converted into a Python object then you should raise an exception. This can be a webob exception (we suggest webob.exc.HTTPUnprocessableEntity), but you could also define your own custom exception and provide a view for it that sets the status to 422. This way conversion and validation errors are reported to the end user.