This example is a full-stack web application, built in a typesafe functional way.
What'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.
- Install Stack and Elm
- Run code generation
cd backend && stack run codegen
- Install frontend dependencies
cd frontend && npm i
- If you are using VSCode and you want to open both frontend and backend as a single workspace, use
File > Open Workspace
and chooseservant-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.
- Start the server on port 8000:
cd backend && stack run server
- Run frontend in dev mode
cd frontend && npm start
- Open http://localhost:8080
- A book can have exactly 1 author
- An author can have zero to many books
- Book title must be unique per author
- The author's name must be unique
- How to fetch data and handle errors and "loading" state
- How to post a new entity related to another, either new or existing one (submit a book with a new or existing author)
- User input
validationparsing best practices - Client-side routing best practices
- Debouncing user input
- Client-side validation before submitting a form
- Subscriptions via WebSockets (which could be implemented, but they are related more to Servant or Elm, rather than to code-generation)
- New entries that are in relation are submitted together and inserted transactionally.
- Search is case-insensitive
- 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.
- in
backend/src/DomainModel.hs
:- Define the type
- 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
, andNewBookAuthor
types and corresponding generated Elm module) - Add the type to
typeDefinitions
list -jsonDefinitions @YourNewType
- Use your type in
backend/src/Server.hs
or wherever it's intended to - Run code-generation again
- 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 thefrontend/src/Api
directory is removed before writing new files. - One of the alternatives to this approach is GraphQL, and there is a Haskell/Elm full-stack GraphQL example app. This example app was shamelessly inspired by that example.