{"id":15059623,"url":"https://github.com/haskell-to-elm/servant-to-elm-example","last_synced_at":"2025-07-26T20:07:05.732Z","repository":{"id":66278765,"uuid":"327174118","full_name":"haskell-to-elm/servant-to-elm-example","owner":"haskell-to-elm","description":"Full-stack web app, built in a typesafe functional way, where servant-to-elm generates types, decoders/encoders, and fetching functions from Haskell types and Servant endpoint definition to Elm.🤘🏻","archived":false,"fork":false,"pushed_at":"2024-05-23T08:49:52.000Z","size":793,"stargazers_count":14,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-07T01:12:29.866Z","etag":null,"topics":["codegen","codegeneration","elm-lang","elm-language","functional-programming","generic-types","haskell","haskell-application","http-client","http-server","servant","typesafe"],"latest_commit_sha":null,"homepage":"","language":"Elm","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/haskell-to-elm.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2021-01-06T02:12:47.000Z","updated_at":"2024-07-25T23:02:57.000Z","dependencies_parsed_at":"2023-11-18T12:29:46.037Z","dependency_job_id":"d8af6e1f-c0f3-493b-9e61-2bdfbd8b4652","html_url":"https://github.com/haskell-to-elm/servant-to-elm-example","commit_stats":null,"previous_names":["haskell-to-elm/servant-to-elm-example"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell-to-elm%2Fservant-to-elm-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell-to-elm%2Fservant-to-elm-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell-to-elm%2Fservant-to-elm-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell-to-elm%2Fservant-to-elm-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/haskell-to-elm","download_url":"https://codeload.github.com/haskell-to-elm/servant-to-elm-example/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248166146,"owners_count":21058474,"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":["codegen","codegeneration","elm-lang","elm-language","functional-programming","generic-types","haskell","haskell-application","http-client","http-server","servant","typesafe"],"created_at":"2024-09-24T22:46:04.146Z","updated_at":"2025-04-10T05:40:51.248Z","avatar_url":"https://github.com/haskell-to-elm.png","language":"Elm","funding_links":[],"categories":[],"sub_categories":[],"readme":"# servant-to-elm-example\n\n![build status](https://github.com/haskell-to-elm/servant-to-elm-example/actions/workflows/build.yml/badge.svg)\n\n\u003cimg src=\"screenshot.png\" alt=\"servant-to-elm-example\" width=\"500\"/\u003e\n\nThis example is a full-stack web application, built in a typesafe functional way.\n\nWhat's cool here is that [servant-to-elm] does the job of generating types and decoders/encoders from Haskell types and [Servant] definition to Elm, which not only catches regressions in the compile-time but also provides ready (and highly configurable) Elm functions to fetch necessary data from the server.\n\n## Prepare\n\n- Install [Stack] and [Elm]\n- Run code generation\n  ```sh\n  cd backend \u0026\u0026 stack run codegen\n  ```\n- Install frontend dependencies\n  ```sh\n  cd frontend \u0026\u0026 npm i\n  ```\n\n### Set up editor (optional)\n\n- If you are using VSCode and you want to open both frontend and backend as a single workspace, use `File \u003e Open Workspace` and choose `servant-to-elm-example.code-workspace`. In this scenario, VSCode will work correctly with both languages simultaneously. Also, the editor may recommend extensions, and installing them is a wise choice.\n\n## Run\n\n- Start the server on port 8000:\n  ```sh\n  cd backend \u0026\u0026 stack run server\n  ```\n- Run frontend in dev mode\n  ```sh\n  cd frontend \u0026\u0026 npm start\n  ```\n- Open http://localhost:8080\n\n## Domain model: Library\n\n- A book can have exactly 1 author\n- An author can have zero to many books\n- Book title must be unique per author\n- The author's name must be unique\n\n## This example does demonstrate:\n\n- [x] How to fetch data and handle errors and \"loading\" state\n- [x] How to post a new entity related to another, either new or existing one (submit a book with a new or existing author)\n\n## This example does not demonstrate:\n\n- User input ~~validation~~ parsing best practices\n- Client-side routing best practices\n- Debouncing user input\n- Client-side validation before submitting a form\n- Subscriptions via WebSockets (which could be implemented, but they are related more to Servant or Elm, rather than to code-generation)\n\n### Other choices\n\n- New entries that are in relation are submitted together and inserted transactionally.\n- Search is case-insensitive\n\n## Technical notes\n\n- This app was not tested on Windows systems yet. While is not a showcase of cross-platform compatibility, you can still open an issue or PR if something does not work as expected.\n\n### Adding new types\n\n- in `backend/src/DomainModel.hs`:\n  - Define the type\n  - Derive necessary instances, also specify Elm module name and Elm type (it's better to keep type name the same, but it's convenient to use one module for several coupled types - see `Book`, `NewBook`, and `NewBookAuthor` types and corresponding generated Elm module)\n  - Add the type to `typeDefinitions` list - `jsonDefinitions @YourNewType`\n- Use your type in `backend/src/Server.hs` or wherever it's intended to\n- Run code-generation again\n\n### Design choices and alternatives\n\n- An obsolete generated Elm code can be removed before writing the new ones. Subdirectories that must be deleted are listed in `backend/src/Codegen.hs`. In this example, only the `frontend/src/Api` directory is removed before writing new files.\n- One of the alternatives to this approach is GraphQL, and there is a [Haskell/Elm full-stack GraphQL example app](https://github.com/higherkindness/mu-graphql-example-elm). This example app was shamelessly inspired by that example.\n\n[stack]: https://docs.haskellstack.org/en/stable/README/#how-to-install\n[elm]: https://guide.elm-lang.org/install/elm.html\n[servant]: https://www.servant.dev/\n[servant-to-elm]: https://github.com/haskell-to-elm/servant-to-elm\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaskell-to-elm%2Fservant-to-elm-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhaskell-to-elm%2Fservant-to-elm-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaskell-to-elm%2Fservant-to-elm-example/lists"}