You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We would also like to raise your attention to an interesting approach to web development based on the [continuation](https://wiki.haskell.org/Continuation). A continuation is "something" that enables you to save the state of computation, suspend it (do something else) and later resume it. This "something" may be a first-class language feature (such as in Scheme), or a library feature - in Haskell, surprisingly, we have a continuation monad ;-).
574
+
To connect the concepts from this tutorial with practical usage, we will briefly outline the architecture of a simple web application based on Servant, which you will use in the assignment.
575
575
576
-
A need for continuation occurs typically in web development (and generally in UI development) when you want a modal dialogue. Today, most of the dialogues are handled on client-side, however if you need to do a modal dialogue on server-side, it is hard - HTTP behaves like a programming language, which does not have subroutines, only GOTOs (URLSs are the 'line numbers'). Continuation can provide the missing abstraction here, which is embodied in the [MFlow](http://mflowdemo.herokuapp.com) library. Sadly, the project seems abandoned for several years.
576
+
The goal is not to explain every detail, but to show how the pieces fit together.
577
577
578
-
At the same time, the continuation-style web server programming is typically the first choice in the Smalltalk (OOP) world - [Seaside](http://seaside.st/) is purely continuation-based, and as such it gives a "desktop programming" experience for the web development resulting in no need of dealing with routing and URLs. As for the FP world, continuation-style web programming is surprisingly not used much in practice, but there are solutions such as the [Racket web server](https://docs.racket-lang.org/web-server/index.html) or [cl-weblocks](https://www.cliki.net/cl-weblocks) in Common Lisp.
578
+
### Why Servant?
579
579
580
+
Servant is a web framework that allows you to define your API at the type level.
580
581
581
-
The next time, we will deal a bit with frontend technologies for Haskell, functional reactive programming and [The JavaScript problem](https://wiki.haskell.org/The_JavaScript_Problem). So you will also see how to develop server-side and client-side separately and connect them through a (REST) API.
582
+
This has several advantages:
583
+
584
+
* the API serves as a single source of truth,
585
+
* server and client can be derived from the same definition,
586
+
* many errors are caught at compile time.
587
+
588
+
Servant is especially well-suited for building REST APIs with JSON.
589
+
590
+
### Application architecture
591
+
592
+
In the assignment, the application follows a simple layered structure:
* Model / DTOs – represent internal data and external API formats
598
+
599
+
This separation helps keep the code:
600
+
601
+
* modular,
602
+
* testable,
603
+
* easier to understand.
604
+
605
+
We intentionally keep the architecture (and naming) close to what you may know from other languages and frameworks to show how Haskell can be used in a familiar way, while still benefiting from its unique features.
606
+
607
+
### Application monad (context)
608
+
609
+
The application uses a custom monad stack (using Monad transformers) to manage the application context, which includes:
610
+
611
+
```haskell
612
+
newtypeAppContextMa=AppContextM
613
+
{runAppContextM::ReaderTAppContext (LoggingT (ExceptTServerErrorIO)) a
* `ExceptTServerErrorIO` =error handling compatible with Servant
623
+
624
+
You have already seen these building blocks — here they are combined into a practical application context.
625
+
626
+
### Example domain: TODO item
627
+
628
+
The application typically works with a simple entity such as a TODO item.
629
+
630
+
You will encounter:
631
+
632
+
* ``Model`` = internal representation used in business logic
633
+
* ``DTOs`` (DataTransferObjects) = types used for JSON input/output
634
+
* ``Conversion functions`` = mapping between internal and external representations
635
+
636
+
### Model and Database
637
+
638
+
The model describes how data are stored in the database.We can define models using **Persistent** library, which provides a nice DSL for defining database entities and their fields.
639
+
640
+
```haskell
641
+
--- ... Database/Model.hs
642
+
643
+
share
644
+
[mkPersist sqlSettings, mkMigrate "migrateAll"]
645
+
[persistLowerCase|
646
+
TODOItem
647
+
title String
648
+
description String
649
+
isDone Bool
650
+
deriving Show
651
+
|]
652
+
```
653
+
654
+
This generates the `TODOItem` type together with database keys and migration support.
655
+
656
+
Similarly to Java frameworks we can create a `Repository` or `DAO` to abstract database operations, but in this simple application, we will directly use Persistent functions in the service layer.
657
+
658
+
```haskell
659
+
--- ... Database/TODOItemDAO.hs
660
+
661
+
getById::String->AppContextM (MaybeTODOItem)
662
+
getById todoId =do
663
+
result <- runDB $ selectList [TODOItemUuid==. todoId] []
run 3000$ serve apiProxy (hoistServer apiProxy (convertAppContext appContext) todoServer)
773
+
```
774
+
775
+
Functions like `initializeAppContext` and `convertAppContext` are responsible for setting up the application context and converting it to the form expected by Servant.
776
+
777
+
### Conclusion
778
+
779
+
This case study shows how to structure a simple web application in Haskell using Servant, Persistent, and a custom application monad. The same principles can be applied to other frameworks and libraries as well. The key takeaway is that Haskell's strong type system and powerful abstractions allow us to build web applications that are modular, testable, and maintainable.
0 commit comments