{"id":15063856,"url":"https://github.com/eldr-io/hastl","last_synced_at":"2025-04-09T07:07:36.388Z","repository":{"id":242590857,"uuid":"809686132","full_name":"eldr-io/hastl","owner":"eldr-io","description":"Production ready, modern web-application starter template using haskell and htmx ","archived":false,"fork":false,"pushed_at":"2024-10-08T17:27:28.000Z","size":72,"stargazers_count":88,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-02T06:07:00.269Z","etag":null,"topics":["alpinejs","hacktoberfest","haskell","htmx","lucid","servant","tailwindcss","template","web"],"latest_commit_sha":null,"homepage":"https://eldr.io/#hastl-modern-web-application-starter-kit","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eldr-io.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-03T08:53:56.000Z","updated_at":"2025-02-24T15:59:05.000Z","dependencies_parsed_at":"2024-08-14T10:08:43.427Z","dependency_job_id":"0a55397b-21fd-4c46-906d-596d9cb9862c","html_url":"https://github.com/eldr-io/hastl","commit_stats":null,"previous_names":["eldr-io/hastl"],"tags_count":0,"template":true,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eldr-io%2Fhastl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eldr-io%2Fhastl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eldr-io%2Fhastl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eldr-io%2Fhastl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eldr-io","download_url":"https://codeload.github.com/eldr-io/hastl/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247994121,"owners_count":21030050,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alpinejs","hacktoberfest","haskell","htmx","lucid","servant","tailwindcss","template","web"],"created_at":"2024-09-25T00:08:02.885Z","updated_at":"2025-04-09T07:07:36.366Z","avatar_url":"https://github.com/eldr-io.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ca name=\"top-of-readme\"\u003e\u003c/a\u003e\n\u003cbr /\u003e\n\u003cdiv align=\"center\"\u003e\n\u003cimg src=\"https://github.com/eldr-io/hastl/assets/83576392/0da858b9-7f42-4be9-aa6f-336332884400\" width=\"50%\" /\u003e\n\n\u003ch3 align=\"center\"\u003eProduction ready, modern web-application starter template\u003c/h3\u003e\n\n\u003cp align=\"center\"\u003e hastl is a modern Haskell web application using \u003cb\u003e(H)\u003c/b\u003etmx, \u003cb\u003e(A)\u003c/b\u003elpine.js, \u003cb\u003e(S)\u003c/b\u003eervant, \u003cb\u003e(T)\u003c/b\u003eailwind-css and \u003cb\u003e(L)\u003c/b\u003eucid. It is based on the awesome \u003ca href=\"https://github.com/parsonsmatt/servant-persistent\"\u003eservant-persistent\u003c/a\u003e example and is licensed under \u003ca href=\"https://github.com/eldr-io/hastl/blob/main/LICENSE.md\"\u003eMIT\u003c/a\u003e and is entirely free and open source.\n\u003c/p\u003e\n\n#### Built with\n\n[![Haskell][Haskell]][Haskell-url]\n[![Htmx][Htmx]][Htmx-url]\n[![Alpine][Alpine]][Alpine-url]\n[![Servant][Servant]][Servant-url]\n[![Tailwind][Tailwind]][Tailwind-url]\n[![Lucid][Lucid]][Lucid-url]\n\nhastl is primarily tested with PostgreSQL but it uses the popular \u003ca href=\"https://www.yesodweb.com/book/persistent\"\u003epersistent\u003c/a\u003e haskell library as an ORM and therefore can be used with most popular databases.\n\n### \u003cimg height=\"20\" width=\"20\" src=\"https://cdn.jsdelivr.net/npm/simple-icons@v12/icons/rocket.svg\" style=\"margin-right: 0.5rem\" /\u003e  Features \n\n\u003cp align=\"left\"\u003e\u003cb\u003eType-safe APIs\u003c/b\u003e - 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\n\u003c/p\u003e\n\u003cp align=\"left\"\u003e\u003cb\u003eModern frontend with htmx\u003c/b\u003e - 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\n\u003c/p\u003e\n\u003cp align=\"left\"\u003e\u003cb\u003eLive reloading with GHCID\u003c/b\u003e - since we're writing almost all of our code in the backend, hastl uses GHCID to instantly reload your project as you make changes\n\u003c/p\u003e\n\u003cp align=\"left\"\u003e\u003cb\u003eIntegration testing with TestContainers\u003c/b\u003e - hastl uses \u003ca href=\"https://testcontainers.com\"\u003etestcontainers\u003c/a\u003e to spin up a database on the fly to run integration tests and give you confidence in your business logic\n\u003c/p\u003e\n\n\n### Get Started\n\u003c/div\u003e\n\nStart by creating a new repo from the hastl template by clicking \"Use this template\" in the top right corner.\n\n#### Setting up dependencies\n\nHastl requires the tailwindcss standalone CLI executable locally in the root folder as \u003ca href=\"https://tailwindcss.com/blog/standalone-cli\"\u003edescribed here\u003c/a\u003e. 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.\n\nThe 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.\n\nNavigate into your cloned repo and run:\n\n```\nmake run\n```\nThis will build and run hastl and you should be able to navigate to `localhost:8081` in your browser and see the hastl demo application:\n\n![Screenshot from 2024-06-08 15-41-54](https://github.com/eldr-io/hastl/assets/83576392/19af0d8e-33b8-411e-a19e-e2e4f8c3420f)\n\nTo run the development live reloading mode, make sure that \u003ca href=\"https://github.com/ndmitchell/ghcid\"\u003eghcid\u003c/a\u003e is installed and then use the watch target:\n\n```\nmake watch\n```\n\n#### Running unit tests\n\nThe unit tests of the project can be found in the `test` directory and can assert things like HTML generation from database types. \n\nYou can run all the unit tests with:\n\n```\nmake test\n```\n\n#### Running integration tests\n\nHastl 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.\n\nThe integration tests manage the containers, starting them and tearing them down as the tests complete.\n\nYou can run all the integration tests with:\n```\nmake test-integration\n```\n\n#### Changing the routes and templates\n\nHastl 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.\n\nIf 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).\n\n#### Documentation Recipes\n\n- [Using UUIDs instead of Integer IDs as Primary Keys in database](https://github.com/eldr-io/hastl/blob/main/docs/recipes/using-uuids-for-db-ids.md)\n\n[Haskell]: https://img.shields.io/badge/haskell-5D4F85?style=for-the-badge\u0026logo=haskell\u0026logoColor=white\n[Haskell-url]: https://haskell.org\n[Htmx]:  https://img.shields.io/badge/htmxjs-3366CC?style=for-the-badge\u0026logo=htmx\u0026logoColor=white\n[Htmx-url]: https://htmx.org\n[Alpine]: https://img.shields.io/badge/alpinejs-8BC0D0?style=for-the-badge\u0026logo=alpine.js\u0026logoColor=white\n[Alpine-url]: https://alpinejs.dev\n[Servant]: https://img.shields.io/badge/Servant-5D4F85?style=for-the-badge\u0026logo=haskell\u0026logoColor=white\"\n[Servant-url]: https://www.servant.dev\n[Tailwind]: https://img.shields.io/badge/Tailwind-06B6D4?style=for-the-badge\u0026logo=tailwindcss\u0026logoColor=white\n[Tailwind-url]: https://tailwindcss.com\n[Lucid]: https://img.shields.io/badge/Lucid-5D4F85?style=for-the-badge\u0026logo=haskell\u0026logoColor=white\n[Lucid-url]: https://hackage.haskell.org/package/lucid2\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feldr-io%2Fhastl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feldr-io%2Fhastl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feldr-io%2Fhastl/lists"}