Haskell on Rails
For my main side project I’m using a stack comprised (of a ton) of hand picked modules, adding or replacing things as I go. This is not unusual in Haskell land: you’re expected to know what you need and figure out how to stick those things together. This approach provides infinite flexibility, but can also cost a lot of time.
Compared to using some of the more well known web frameworks like Ruby on Rails, Django or Spring Boot, the amount of elbow grease you’ll need to put in with your Haskell web app can seem especially daunting.
There are a lot of amazing libraries in the Haskell ecosystem that can fulfill all your web dev needs. But, when it comes to a comprehensive web framework, there aren’t many options for the Haskell programmer. In fact I can only think of two: Yesod, and now Integrated Haskell Platform. The latter is what I’ll be writing about in this post.
Integrated Haskell Platform
For a while I’ve been meaning to test out Integrated Haskell Platform, formerly known as TurboHaskell and probably known by another name in the future. Now, trying out different web dev tooling is something I tend to almost never do. Once I’ve got things set up and they work, I just want them to “stay out of my way”. However, IHP looked very interesting so I thought I’d break my habit.
The introduction sounds very promising, it reads:
"IHP is a full stack framework focused on rapid application development while striving for robust code quality."
Rapid AND robust, what’s not to like? The page goes on to say they try to…
“…offer a solution which can be used by developers who have not worked with Haskell yet.”
This is an exciting claim, and I really hope it holds, so we can start off people who “just want to build a web app” with strong foundations.
Installation and development server
I’ll be following the “Your first Project” guide on the Getting started page. To get everything bootstrapped IHP uses the Nix Package manager. The installation process is very smooth (although I did already have nix installed). Once it finishes, a terminal command for generating new projects becomes available: ihp-new.
# usage ihp-new PROJECT_NAME
Run ihp-new with a name of your choice. After some time your application will be ready, and you’ll have a directory called PROJECT_NAME. Navigate into that directory, and start the development server by running the executable file named ‘start’.
cd PROJECT_NAME ./start
This serves the application, a postgres database, and a slick developer UI (pic below). So far so good, now let’s go build something.
Modeling our data
Remember that IHP boots a database for local development? We can now model our database without writing any SQL. The UI has a page called “SCHEMA” where you can create and alter the database schema, and another page called “DATA” where you can insert rows. I added a new table and some columns by right clicking and selecting “Add column”, then typing a name and checking a couple boxes to enforce uniqueness constraints. Then I inserted a row through the other UI.
A nice touch is that when you want to add a column that references a different table’s column, all you have to do is follow the naming convention “othertablename_id” and the ui will detect and set up the foreign key reference.
If you’re interested in seeing what Haskell types get defined from your database model: right-click the table-name and select “Show Generated Haskell Code”.
IHP generates database queries written with Postgres Simple which is a very stable and easy to use postgres client library. For any table with more than a couple columns this is exactly the kind of boilerplate code I’d be happy to not write myself.
Schema changes made through the UI get written to the file found at ‘Application/Schema.sql’. This is just a regular, flat, SQL file. I’m assuming this what we’ll use to deploy the database to our production server. Important to note is that in addition to the mouse driven approach, the UI also offers the option to directly edit the SQL file.
Generating a Controller
After creating a simple table using the schema editor, we’ll add a Controller in order to retrieve my data. The “CODEGEN” page has a button for it. All you do is choose a plural name e.g. Posts, it then shows a preview of all the code that it will generate, and then you click once more to apply the changes. The preview screen makes it very clear which files are new, and which files get modified. In short, this is what was generated:
- HTTP endpoints using the format CreatePost, UpdatePost, etc.
- The “Controller”. It contains “actions” which perform the CRUD calls.
- A set of “Views” that generate html pages with forms to perform the CRUD calls.
Have a look at your new pages, located at localhost:8000/Posts.
Views and Forms
Views are written using HSX, a quasiquoter custom made for IHP. It allows you to write html directly inside your Haskell source files. If you’re familiar with React’s JSX syntax, that’s basically what HSX is. Under the hood it uses the well established html generating library blaze-html.
First time breaking things
When choosing my table name, I chose the name “words”. This caused the application to not compile, since the generated “Word” instance clashed with imports from various modules throughout the application. This could probably have been avoided by using qualified imports. Even so, the error message is clear to me: “Ambiguous occurrence `Word’, it could refer to … or …” but now there’s no way for me to roll back the generated code. Note to self: commit things to source control before altering the schema or using the code generator. I can now either start over (since it takes very little time) or undo the generated code by hand. In this case I started over, to see how far I could get without modifying any source code.
There’s a lot more features to explore such as authentication and authorization, database migrations, connecting to differnet front-ends, etc. etc. But for now I want to wrap up this post:
IHP was made open source after being used in production for multiple years, and it shows. Everything seems to be designed around the most frequently encountered problems when building web applications. The documentation, which is still very much being written, has many good examples of how to make things work and clearly describes design choices. Time will tell how much friction the pragmatic approach causes when applications grow and become more complex. But right now, I don’t know of any other tool in the Haskell ecosystem that allows you to set up a web application in such a straightforward manner as IHP, without prior Haskell knowledge.
Make sure to read the official documentation (it’s very good), which I only did after breaking things