![](https://private-user-images.githubusercontent.com/83576392/337896988-0da858b9-7f42-4be9-aa6f-336332884400.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQ0NTg0ODIsIm5iZiI6MTcyNDQ1ODE4MiwicGF0aCI6Ii84MzU3NjM5Mi8zMzc4OTY5ODgtMGRhODU4YjktN2Y0Mi00YmU5LWFhNmYtMzM2MzMyODg0NDAwLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MjQlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODI0VDAwMDk0MlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPThiMDM0Y2NjMzZjNzEwMjQzNTRhOGNlNDc1YjBjZWJiMjlmZWM1ODQyY2QzYjc1ODQ3YTA5ODhlMWNlZDJjMDAmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.moNH66IXCqCY_LK39GQ8xuLBtOrsV7VYJwX7dJmXgc0)
hastl is a modern Haskell web application using (H)tmx, (A)lpine.js, (S)ervant, (T)ailwind-css and (L)ucid. It is based on the awesome servant-persistent example and is licensed under MIT and is entirely free and open source.
hastl is primarily tested with PostgreSQL but it uses the popular persistent haskell library as an ORM and therefore can be used with most popular databases.
Type-safe APIs - hastl uses Servant to define APIs that make up the application, providing type safety and consistency across the application, with the haskell type-checker keeping you honest as you develop
Modern frontend with htmx - the use of htmx in hastl allows you to build modern user interfaces with the simplicity and power of hypertext, with haskell and lucid2 doing the heavy lifting
Live reloading with GHCID - since we're writing almost all of our code in the backend, hastl uses GHCID to instantly reload your project as you make changes
Integration testing with TestContainers - hastl uses testcontainers to spin up a database on the fly to run integration tests and give you confidence in your business logic
Start by creating a new repo from the hastl template by clicking "Use this template" in the top right corner.
Hastl requires the tailwindcss standalone CLI executable locally in the root folder as described here. In addition, it expects a local postgreSQL database to be running on port 5432, alternatively use the provided compose.yaml file to run either Podman or Docker to spin it up.
The project includes a Makefile to provide you with convenient targets for running the server in development mode as well as running the tailwindcss CLI in watch mode to generate stylesheets on the fly.
Navigate into your cloned repo and run:
make run
This will build and run hastl and you should be able to navigate to localhost:8081
in your browser and see the hastl demo application:
To run the development live reloading mode, make sure that ghcid is installed and then use the ghcid-devel target:
make ghcid-devel
The unit tests of the project can be found in the test
directory and can assert things like HTML generation from database types.
You can run all the unit tests with:
make test
Hastl ships with built-in integration tests that use testcontainers to start a local postgreSQL database inside a container (using docker or podman) on-the-fly, as well as running the project web-server, allowing the tests to exercise the actual HTTP endpoints to assert correctness.
The integration tests manage the containers, starting them and tearing them down as the tests complete.
You can run all the integration tests with:
make test-integration
Hastl allows you to combine strongly-typed Servant APIs to make up your application. To add a new route and endpoint, you can create a new file similar to lib/Api/Guest.hs
e.g. if you wanted to create a Todo-list API you could create lib/Api/Todo.hs
. Additionally, you can create a new directory within lib/Api/Templates
to store your Lucid-powered Haskell template files. Within the template files, you have access to the full power of HTMX and Alpine through helper functions.
If you wish to use persistent models in your application, you can define your models in lib/Models.hs
and persistent will automatically create the Haskell types, as well as handling the database migrations for DEVELOPMENT setups (note: is it recommended to use a more robust migration mechanism for production).