To continue exploring the design of a generic database user interface, let us turn our attention to a web interface. I’ll use the pattern of the Django admin application as the basis for specifying the behavior of a somewhat RESTful web interface for maintaining the movies database I’ve used in previous posts.
Home Page
The home page (canonically at http://www.example.com/) is comparable to the menu displayed initially by the command line interface (CLI). It will consist of an HTML table listing the logical entities together with options to add a new record (New) or edit an existing one (Edit). For now, the table will include a single entity: a film.
The latter option (or the entity link itself) will take the user to the List Records Page (see below). The New option will go to the
Add Record Page
This will be presented at http://www.example.com/film/new and is comparable to the Add interactions in the CLI. It will have an HTML form with fields (HTML text input or textarea elements) for each attribute and a “Save” button (HTML submit input element). Pressing the button will POST the new data to http://www.example.com/film/create.
List Records Page
This is of course comparable to the CLI List display. It will feature an HTML table listing all films. This is the index page for the entity so its URL will be http://www.example.com/film/.
We’ll worry about pagination later, but when we do the URL will have a query string to select a given page, e.g., http://www.example.com/film/?p=123.
Each row of the HTML table will have a link that leads to the
Record Edit Page
This will have a URL that identifies the film being edited, e.g., http://www.example.com/film/23969, where 23969 corresponds to a value in the id column of the film table in our database. This is equivalent to the CLI Update option.
The Edit page will have the same HTML form as the Add Record page, including the “Save” button, but the POST will go to http://www.example.com/film/save/23969. It will also have a “Delete” link that goes to the
Record Delete Confirmation Page
This will be presented at http://www.example.com/film/delete/23969 and is comparable to the confirmation requested by the CLI Delete. It will display an “Are you sure?” message together with details of the record to be deleted and a button titled “Yes, I’m sure.” The POST will use the same URL as the GET.
Form and Error Handling
Both the Add and Edit pages will validate the data entered. If there are any errors, the respective page will be redisplayed with a message(s) indicating what needs to be corrected. If a “Save” operation succeeds, we’ll redisplay the film listing.
Entity Handler
With this specification, if we translate each URL path above into a class method, we can outline a Python class that will act as the handler (or MVC controller, although Django calls this the view layer) for the HTTP requests. Note that the entity index URL (the listing) maps to the index method while the specific entity URL maps to the default method.
class FilmHandler(object): def new(self): "Displays a form to create a new film" pass def create(self, **formdata): "Saves the film submitted from ``new``" pass def index(self): "List all films" pass def default(self, id=None): "Displays a form for editing a film by id" pass def save(self, id=None, **formdata): "Saves the film submitted from ``default``" pass def delete(self, id=None): "Deletes an existing film by id" pass
There are many more details such as the “Model,” i.e., the interface to the database itself, and the MVC View (which Django calls the template layer). So visit again if you’re interested!
Update: Changed title and first paragraph to emphasize that the interface does not adhere strictly to the REST canon. See Oliver Charles’ detailed critique below.
I’m really sorry, but this isn’t REST at all.
Would you care to explain why you think this interface isn’t RESTful?
Berend is correct, this is much more RPC, and barely REST.
“Add Record Page: This will be presented at http://www.example.com/film/new” This isn’t really part of REST at all (unless the new film page happens to be a resource), so it’s debatable how correct it is. Obviously you need somewhere to create films from though, so this seems acceptable.
“Pressing the button will POST the new data to http://www.example.com/film/create”
No, the form should POST to /films. Notice I’m using a plural resource here too. POST means “append to this resource” so we are appending a new film to the films resource.
“List records page” Should be /films, not /film.
“Record Edit Page” again, not part of REST – because REST isn’t concerned with the user interface. However, /film/{id} should fetch the film resource primarily, if you want to add an edit form their that should be that URIs *secondary* purpose.
“The Edit page will have the same HTML form as the Add Record page, including the “Save” button, but the POST will go to http://www.example.com/film/save/23969”
No. The edit form, wherever it is, should be a PUT request to /film/{id}. PUT means “replace content” effectively.
“http://www.example.com/film/delete/23969″ Should be /film/{id}/delete (hierarchical URI). It should also submit DELETE /film/{id} (sending a DELETE request to the resource being deleted).
Thanks for the detailed response. As I stated early in my post, I was following the Django admin pattern, so perhaps that’s not as RESTful as some would think. For the record, the URLs for a test Django admin app, are as follows:
/admin/ — Menu, lists “Films” with Add and Change buttons
/admin/test/film/ — List of films
/admin/test/film/add/ — Add a film page
/admin/test/film/add/ — URL to which “add” is POSTed
/admin/test/film/{id}/ — Change film page
/admin/test/film/{id}/ — URL to which “change” is POSTed
/admin/test/film/{id}/delete/ — Delete confirmation page
/admin/test/film/{id}/delete/ — URL to which “delete” is POSTed
So, perhaps the title of my post shouldn’t have been “Designing a RESTful Database User Interface” but rather “Designing a Django-admin-like Database User Interface.” In any case, this will probably not be the final design, but more an exploration of an interface that I have found useful.
To give proper credit where it’s due, the design was also influenced by James Gardner’s SimpleSite tutorial (available here).
Hi Joe,
Interesting article. I am a recent Python convert and have been trying to design my own generic template database CRUD classes which (I’m pleased to say) have turned-out similar to your FilmHandler example. If you are willing to disclose it, I would be interested to see what generic code you have inside the new, create, save, etc. methods within the class. Is that possible, or is it something you had planned to post to the blog in the future?
Regards,
Alan
Hi Alan,
The idea behind these series of posts is to develop a database interface application generator for Pyrseas, somewhat like Andromeda has. So yes, I’ll be disclosing more of the generic code as I go along.
Joe
Pingback: Joe Abbate: Designing a RESTful Database User... | PostgreSQL | Syngu
Pingback: A Minimalist WSGI Database User Interface | Taming Serpents and Pachyderms
Pingback: Dueling Frameworks, revisited | Taming Serpents and Pachyderms