Haskell on Rails
Introduction
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.
Sidenotes:
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.
IHPâs HSX is currently (2020-10-26) not available as a package on Hackage, but the developers intend to put it up there. Be aware that this has nothing to do with the xml quasiquoter hsx2hs.
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.
Conclusion
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