When you POST a new customer @id is not needed, but it gets added after POST . The response to a POST should be JSON representing the new customer we just POSTed, but now with the @id added.

The customer collection JSON at /customers looks like this:

What's this @id and @type business? They're just conventions (though I took them took from the JSON-LD standard). @id is a link to the customer itself, which also uniquely identifies this customer. @type describes the type of this object.

The customer JSON at /customers/{id} looks like this:

Moreover, you want to POST JSON to it that represents a new customer, to add it a customer to the collection.

This represents a collection of customers. You want to be able to GET it and get some JSON information about the customers back.

There's also the URL:

When you access it with a GET request, you get JSON describing the customer with the given id, or if it doesn't exist, 404 Not Found.

You want to support the URL (hostname info omitted):

Say you're implementing a REST API (also known as a hypermedia API).

Here's the scenario we are going to implement.

Implementing this scenario with Morepath

First we define a class Customer that defines the customer. In a real-world application this is backed by some database, perhaps using an ORM like SQLAlchemy, but we'll keep it simple here:

class Customer ( object ): def __init__ ( self , name ): self . id = None # we will set it after creation self . name = name

Customer doesn't know anything about the web at all; it shouldn't have to.

Then there's a CustomerCollection that represents a collection of Customer objects. Again in the real world it would be backed by some database, and implemented in terms of database operations to query and add customers, but here we show a simple in-memory implementation:

class CustomerCollection ( object ): def __init__ ( self ): self . customers = {} self . id_counter = 0 def get ( self , id ): return self . customers . get ( id ) def add ( self , customer ): self . customers [ self . id_counter ] = customer # here we set the id customer . id = self . id_counter self . id_counter += 1 return customer customer_collection = CustomerCollection ()

We register this collection at the path /customers :

@App.path ( model = CustomerCollection , path = '/customers' ) def get_customer_collection (): return customer_collection

We register Customer at the path /customers/{id} :

@App.path ( model = Customer , path = '/customers/{id}' converters = { 'id' : int }) def get_customer ( id ): return customer_collection . get ( id )

See the converters bit we did there? This makes sure that the {id} variable is converted from a string into an integer for you automatically, as internally we use integer ids.

We now register a dump_json that can transform the Customer object into JSON :

@App.dump_json ( model = Customer ) def dump ( self , request ): return { '@type' : 'Customer' , '@id' : self . id , 'name' : self . name }

Now we are ready to implement a GET (the default) view for Customer , so that /customer/{id} works:

@App.json ( model = Customer ) def customer_default ( self , request ): return self

That's easy! It can just return self and let dump_json take care of making it be JSON.

Now let's work on the POST of new customers on /customers .

We register a load_json directive that can transform JSON into a Customer instance:

@App.load_json () def load ( json , request ): if json [ '@type' ] == 'Customer' : return Customer ( name = json [ 'name' ]) return json

We now can register a view that handles the POST of a new Customer to the CustomerCollection :

@App.json ( model = CustomerCollection , request_method = 'POST' , body_model = Customer ) def customer_collection_post ( self , request ): return self . add ( request . body_obj )

This calls the add method we defined on CustomerCollection before. body_obj is a Customer instance, converted from the incoming JSON. It returns the resulting Customer instance which is automatically transformed to JSON.

For good measure let's also define a way to transform the CustomerCollection into JSON:

@App.dump_json ( model = CustomerCollection ) def dump_customer_collection ( self , request ): return { '@id' : request . link ( self ), '@type' : 'CustomerCollection' , 'customers' : [ request . link ( customer ) for customer in self . customers . values () ], 'add' : request . link ( self ), }

request.link automatically creates the correct links to Customer instances and the CustomerCollection itself.

We now need to add a GET view for CustomerCollection :

@App.json ( model = CustomerCollection ) def customer_collection_default ( self , request ): return self