Web application with Pedestal16 May 2015
As Frankie said, for web development in Clojure we should give Pedestal another chance. So I set out to build a user facing web application with Pedestal. To me a minimally useful user facing web application should have a database, templating, forms, authentication and authorization. And for development I like to get something I can click through as soon as possible, as well as having a dynamic development process from the REPL. The w3a library and w3a-example try to provide this, using Pedestal as foundation.
The example application is running on Heroku at https://w3a-example.herokuapp.com. The functionality is loosely inspired by Django Rest Framework example application, but the implementation is not. This means the example contains CRUD-like data pages, users accounts, forms, pagination and breadcrumb navigation. The interesting code in the w3a-example is in the service.clj file.
w3a uses components with Pedestal to organize the app and to provide an in-memory database for development and to leave out the jetty webserver during testing. Migrations and fixture loading are also components
Data, links & forms
The basic parts of a page in a CRUD web application are data, links and maybe a form. The data is whatever the application is about, the links make it a web application and the form makes the application slightly more interesting than a static web page.
With w3a the aim is to be able to specify the data, links and forms as an EDN api first and then later decorate this with a template to serve HTML. To serve HTML the data is transformed with Enlive. The EDN api returns a 201 status for a created resource and a 400 status when something failed validation. This is not the functionality users expect when browsing through HTML pages, so w3a transforms those to 303 redirects and re-rendered form pages with the validation errors added. To aid the development of the EDN api a click-througable HTML version is served in browsers. This is available by appending the ?format=dev parameter.
context, context everywhere
Sometimes it is claimed that web development in Clojure only
requires the composition of libraries. While this is true, for me
this is almost always a frustrating exercise. In particular when the
composition requires composing database access, sessions and user
In Pedestal everything goes through interceptors, which take the context as an argument. This context consists of the request, response and other user defined content. I have started to simple pass the context everywhere. In link generators, validation functions, templating and everywhere else. You could argue that this is not much better than global objects or injected bindings everywhere, but I prefer it as I always end up needing just a little part of the context somewhere deep down in the composition. To make using the context everywhere less verbose I use the combine function from Liberator.
Links and breadcrumbs
Pedestal has great support for generating links, as the routing
table doesn't just parse links to call the appropriate handler, it
generation based on the routing table. This also makes it easy
to define links as part of the data. For instance, the link to
edit a snippet is only included in the data
when the user is logged in as the owner of a snippet. This would be
awkward to do by constructing links out of strings everywhere.
In w3a the routing table is also used to generate breadcrumbs. This makes it easy to quickly being able to click through the application, particularly early in development.
Forms through bindings
Defining and rendering forms with validations in w3a is done with bindings. The name is taken from the Go library binding. While it is extensible, it is currently very minimal. Also the way to define which data goes with which binding definition can be improved.
For testing web applications in Clojure there are the Kerodon and Peridot libraries. They are both designed for use with Ring, but with some adjustments can be made to work with Pedestal to test the HTML and EDN functionality.
Pedestal is indeed worth another look. For my use case for user facing web applications it is also a good foundation.