Yesod

Adding GHCJS to equation

September 26, 2016 GHCJS, Haskell, Yesod No comments

In this post we’ll try to remove the JS-ey part of our application – the Julius templates. Before we move on to the actual implementation, I have to warn you: GHCJS is not yet a fully mature project and installing it on Windows platform is a pain. I wasted nearly two days trying to do it using stack, mostly due to a problem with locale – The Internet said it’s already solved, but for some reason it didn’t work. Only the solution described in https://github.com/commercialhaskell/stack/issues/1448 worked – setting non-UTF application locale to en_US) – still, that’s not all. I also had to install pkg-config (this StackOverflow question is about “how to do it”) and nodejs, and that’s still not all – older versions of GHCJS (for example one proposed on Stack GHCJS page) have some trouble with Cabal. In the end, I had to install GHCJS from sources on Windows. Surprisingly, it went without serious problems.

On Linux machines it also requires nasty hacks – like symbolic link from node to nodejs. During standalone installation this can be solved by --with-node nodejs flag, but not on stack installation (unless it’s somehow configurable in stack.yaml, which I’m not aware of).
Installation takes really long – I suppose it was over an hour and downloaded like, half of The Internet.

Anyway, since I’ve managed to do it, you should be able to install it too (if you’re not – write in comments, maybe I can help?), so let’s go to teh codez!
First let’s create the GHCJS project, as a subproject to our main one. Go to main project directory and run stack new ghcjs. That created some files, but – surprisingly – not related to GHCJS in any way. To request compiling it with GHCJS, you have to add the following code to your stack.yaml:

resolver: lts-6.18
compiler: ghcjs-0.2.0.9006015_ghc-7.10.3
compiler-check: match-exact
setup-info:
  ghcjs:
    source:
      ghcjs-0.2.0.9006015_ghc-7.10.3:
        url: "https://tolysz.org/ghcjs/lts-6.15-9006015.tar.gz"
        sha1: 4d513006622bf428a3c983ca927837e3d14ab687

If you are wondering where did I get these paths from (and you should be – never trust an unknown blogger asking you to install some arbitrary packages!), it’s from a ghcjs-dom GitHub issue.

After that run stack setup and spend some time solving the problems (it takes some time, not counting really long installation). For example, if you’re using Windows, you won’t be able to set up environment, because this package uses a particular resolver – lts-6.15, which has a built-in version 0.8.18.4 of yaml package, which cannot be built on Windows, because it contains non-ASCII characters in the path (its this problem). Seriously, that’s one of weirder problems I’ve encountered. Bad news is that it’s not possible to elegantly solve it. I changed manually the downloaded package to use lts-6.18 resolver, which works fine. If you choose this solution, remember to remove sha1 from stack.yaml. Also remember that creating tar.gz files on Windows work a bit differently than on Linux and you may have trouble during repacking (luckily, 7-Zip offers an in-place change feature, which solves this issue).

And voila – we’re ready to code!
First, let’s check whether the current version (which – by default – does only some printing to the console) works with Yesod.
To do that, first compile the GHCJS project (simply stack build), then copy all.js file from .stack-work/install/[some-hash]/bin/*.jsexe to a new directory, static/js. Then we need to includ this file – this is a little cumbersome in Yesod, but adds to type-safety. In desired handler (in our case Project.hs) you have to add addScript $ StaticR js_all_js to implementation of renderPage. The way of inclusion is a bit weird (substituting all slashes and dots with underscores), but guarantees compile-time safety (if the file does not exist, the app will not compile), which is good.

After these changes, run stack exec -- yesod devel. Here’s a fun fact: most probably it won’t compile, saying that js_all_js is not in scope. Thanks to this StackOverflow question we can detect the problem – Yesod didn’t recognize a new static file (identifiers are automatically generated for them). You need to either change or touch Settings/StaticFiles.hs, and after recompilation it’ll work.

Now run the server and open a project. And yay, it works! You can verify it by someFunc print in the JavaScript console. So far so good, now we have to find a way to perform the same action we did in project.julius. There are three steps to perform:

  1. Hook on #delete-project button
  2. onClick – issue a DELETE request
  3. after a response is received – redirect user to site of response

In JavaScript it was really simple, how will it look like in Haskell? Let’s find out!
First thing we need to do is adding ghcjs-dom to our dependencies: extra-deps: [ghcjs-dom-0.3.1.0, ghcjs-dom-jsffi-0.3.1.0] to stack.yaml (FFI is also required) and to .cabal file. Turns out we also have to add ghcjs-base-0.2.0.0 to stack.yaml, but apparently it’s not a published package… luckily, stack can address this. To packages field in stack.yaml add:

- location:
   git: https://github.com/ghcjs/ghcjs-base.git
   commit: 552da6d30fd25857a2ee8eb995d01fd4ae606d22

this will fetch the latest (as of today) commit from ghc-js. This is version 0.2.0.0, so it’ll compile now, right? Right. But wait we didn’t code anything yet! Oh dear, let’s fix it now.

Open the ghcjs/src/Lib.hs file and write:

module Lib (setupClickHandlers) where

import GHCJS.DOM
import GHCJS.DOM (runWebGUI, webViewGetDomDocument)
import GHCJS.DOM.HTMLButtonElement (castToHTMLButtonElement)
import GHCJS.DOM.Document (getElementById)
import GHCJS.DOM.EventTarget
import GHCJS.DOM.EventTargetClosures
import GHCJS.DOM.Types

setupClickHandlers :: IO()
setupClickHandlers = do 
  runWebGUI $ \webView -> do
    Just doc <- webViewGetDomDocument webView
    Just element <- getElementById doc "delete-project"
    button <- castToHTMLButtonElement element
    clickCallback <- eventListenerNew printNow
    addEventListener button "click" (Just clickCallback) False

printNow :: MouseEvent -> IO()
printNow _ = print "Clicked!"

We won’t get through all the imports (I was heavily inspired by some GitHub examples) – it is possible that some of them aren’t necessary, and others can definitely be scoped. Nevertheless, I think that going through the code will be hard enough, so let’s ignore the details for now.

First call, runWebGUI, is responsible for setting our code in proper context. It calls given function (a lambda, in our case) with the GUI view. It’s pretty cool that you can use exactly same code for both the browser and native GTK apps (with proper linkage, obviously). Then we extract the document DOM from the GUI and desired button from the document. In the next line, we create a callback (from function defined a few lines lower), and attach it to "click" event of our button. The syntax for the listener might seem a bit weird, so let’s take a look at the signature and definition:

addEventListener ::
                 (MonadIO m, IsEventTarget self, ToJSString type') =>
                   self -> type' -> Maybe EventListener -> Bool -> m ()
addEventListener self type' listener useCapture

The first two arguments – event target (button) and event type (click) are fairly intuitive, but why is EventListener a Maybe, and what is useCapture? useCapture is a parameter controlling the way of event propagation. It’s explained in more detail here (link from ghcjs-jsffi source). Unfortunately, I still do not know why is EventListener a Maybe – possibly to allow change of event propagation without any actual handler? If you have an idea, let me know in the comments!

You also need to call this function (instead of someFunc) in app/Main.hs. Then compile, copy all.js to static/js (just like before) and remove templates/project.julius file. Now, be careful, this might hurt a little: yesod devel alone won’t spot that you’ve removed the file, so you’ll get 500: Internal Server Error when project.julius should be used.

The current version implements 1st point from our checklist – we’ve added a hook on #delete-project button. Now is the time for some bad news – we won’t be able to easily use Yesod’s typesafe routes. Obviously, we can work around it by generating an interface file – but that’s another level of infrastructure we need to build. That’s why we’ll leave typesafe routes for now and stick with typical strings.

With that knowledge, let’s implement the AJAX call:

data DeletionResponse = DeletionResponse { target :: String } deriving (Generic, Show)
instance ToJSON DeletionResponse where
  toEncoding = genericToEncoding defaultOptions
instance FromJSON DeletionResponse

makeRequest :: String -> Request
makeRequest projectId = Request {
  reqMethod = DELETE,
  reqURI = pack $ "/project/" ++ projectId,
  reqLogin = Nothing,
  reqHeaders = [],
  reqWithCredentials = False,
  reqData = NoData
}

requestProjectDeletion :: String -> IO (Response String)
requestProjectDeletion projectId = xhrString $ makeRequest projectId

deleteProject :: MouseEvent -> IO()
deleteProject _ = do 
  currentLocation <- getWindowLocation
  currentHref <- getHref currentLocation
  response <- requestProjectDeletion $ unpack $ extractLastPiece currentHref
  redirect currentLocation currentHref response
  where
    redirect currentLocation oldHref resp = setHref (pack $ getTarget oldHref resp) currentLocation
    extractLastPiece href = last $ splitOn' (pack "/") href
    getTarget fallback resp = maybe (unpack fallback) target $ ((BS.pack `fmap` contents resp) >>= decode

I’ve also added a few imports (Data.JSString, JavaScript.Web.XMLHttpRequest, JavaScript.Web.Location, GHC.Generics, Data.Aeson and Data.ByteString.Lazy.Char8 as BS) and a language extension – DeriveGeneric, for automatic generation of Aeson serialization/deserialization routines. Of course, this required changes in cabal file as well (aeson and bytestring dependencies). deleteProject becomes our new clickCallback and it works the same way as earlier again!

Now, that’s quite a lot of code, so let’s go through it and examine what happens there.
We start with definition for our response data type – to be honest, it’s not really necessary, and we could’ve just extracted the target field from the response JSON, without intermediate Haskell objects. If GHCJS offers some helpers to do that (with Aeson alone it wouldn’t be much simpler), it could spare us a few packs and unpacks.
Next we create a HTTP request – only variable part here is URI, determined by projectId. An important thing to note is that this code works slightly different thatn the previous version (in Julius) – we only have one code and it dynamically determines routes – previously a separate code was generated and sent with each page, which could add to delays (if it got bigger). Files generated by GHCJS are fairly big (hundreds of kBs), so we can’t really afford sending dozens of them to each user – network bandwidth might be cheaper than earlier, but it won’t be cheap enough to simply throw the throughput away.
Fun fact: the first time I’ve implemented it in a way that it compiled, I mistyped the route. Lack of static typing for routes is quite sad, but probably solvable with some work.
And then, after a short AJAX wrapper, we have the main event listener – deleteProject. It starts with determining the current path, for two reasons – first, that’s the location to set if something goes wrong (“no change”), and second – to determine ID of project. While it works now, it poses several threats. First of all, if two teams work separately on frontend and backend, at some point the route will change (probably without notice) and this mechanism will break. This can be of course prevented with thorough testing and strict processes, but there is also second problem – no URL minifiers will work. While this might not be a problem, it may become one when you switch to MongoDB identifiers.
Next line might be one of the most interesting features of Haskell in asynchronous applications. Due to lazy I/O, we can request redirection to be performed “when data is ready” (after response is received – response is required to proceed here). That’s a really nice solution compared to chains of promises (which are also really nice compared to typical Node.js callbacks), which doesn’t break the code flow but – at the same time – performs implicit waits wherever needed.

The time has come for some final thoughts – after all, we managed to implement the same (or at least very similar), simple functionality using GHCJS and Julius. From my perspective, using GHCJS for simple scripts is a vast overkill – JavaScript is sufficient for it, and if you want more type safety, choose TypeScript (it is also supported in the Shakespearean family). You get out-of-the-box integration with Yesod, a simple type system and route interpolation. That might not be much, but remember that right now we’re aiming for rather simple scripts. And hey – people write *big* apps in JavaScript with no types, so a few lines are not a tragedy (if required).
As for GHCJS – it’s a powerful and promising tool, but still very immature. It’s targets are ambitious, but for now it simply isn’t usable (at least on Windows) – that’s simply unacceptable for an installation from packages to take over two days and require to look through dozens of GitHub issues. Installation from sources might be more convenient, but I expect a mature tool to provide an installable package (even if all the package does is instrumenting the entire compilation locally). And more importantly – if it provides any package, it should work out-of-the-box (regardless if it’s old or new – assuming it’s the newest one, older may have bugs). Right now start-up overhead is simply too big to be acceptable, at least for me (over a half of this post is just about setting up GHCJS!). Programming in it is quite nice, but documentation is ultra-sparse, and most of the stuff has to be looked up in the source – that’s also not what I’d expect from a mature tool. Nevertheless, GHCJS caught my attention and I’ll definitely take a closer look at it again in several months. Maybe then it’ll be possible to apply it to some bigger project (for small ones infrastructure costs – setups, installations etc. – are much too high for me).

Looks like I’ll have to look for a different tool for frontend development (assuming I’m not happy with interpolated JavaScript/TypeScript/CoffeeScript, which is true). I’m going to consider Elm as the next tool – while it’s not exactly Haskell, for a first glance it looks quite haskelly, has static types and several other nice features, as well as decent performance and some Yesod integration. Perhaps it’s worth checking in one of the next posts?

Stay tuned!

Testing the app

September 8, 2016 Haskell, Languages, Testing, Yesod No comments

Every application with a reasonable complexity obviously has to be tested before releasing to the customer – Yesod applications are no different in this case. Of course, type safety gives us a strong guarantees – guarantees which are far beyond reach of Django, Rails or Node developers. Still, that’s not enough to purge all the bugs (or at least most of them). That’s why we have to write tests.

There are hundreds of levels of testing that are specified by dozens of documents, standards and specifications – we won’t be discussing most of them here, as there are only a few people that care about technicalities, and most of us care only about “what to do to make the app work and guarantee that it will keep working”. Formally, these are tests of the functionality (there are also other groups, like performance or UX), and are the most common group of tests. For our application, I’d divide it into three or four kinds of tests that require different setups and different testing methods (we won’t be implementing all of them here – that’s just a conceptual discussion):

  • Unit tests
  • Server (backend) tests
  • Interface (frontend) tests
  • System tests

They become needed with the increasing complexity, so you won’t necessarily need all of them in your first project, but with time, they become increasingly useful (so do performance tests and UX ones, but they are a different story). Unit tests are one of the most popular tools, and pretty much everybody claim that they use it – it’s the basic tool for assessing application sanity in unityped languages (like Python or JavaScript). Of course, Haskell also has several frameworks for writing them, of which ones of the most popular are Tasty and Hspec. Tasty is a framework, but the actual tests and assertions are provided by other libraries, like QuickCheck, SmallCheck or HUnit. The third one is quite a typical xUnit library for Haskell, but the first two are a bit different – instead of testing specific input/output combinations, they are testing properties of your code. They do this by injecting pseudo-random values and analyzing features of the result (instead of the result value). For example, we if the define that prepend is a function which – after applying it to a List – increases its length by 1 and is the first element of the new structure, we could define it as:


prepend :: a -> [a] -> [a]
prepend elem list = elem : list

x = testGroup "prepend features" 
  [
    QC.testProperty "after prepend list is bigger" $ 
      \list elem -> (length $ prepend elem (list :: [Int])) == length list + 1,
    QC.testProperty "after prepend becomes first element" $ 
      \list elem -> (head $ prepend elem (list :: [Int])) == elem
  ]

of course, there are lots of different properties that can be assessed on most structures. However, there is a catch in these tests – you cannot ignore intermittent failures. Since they use random input (pseudo-random, but the seed is usually really random), every test failure may be an actual bug. Plus, it’s possible that some bugs will go unnoticed for a few runs. That’s a bit different philosophy from the usual approach, where data is always the same and bug is either detected or not on each run (assuming no environment “intermittent” failures). It’s not better or worse, it’s simply different. Arguably better for lower-level tests, such as unit tests, and that’s why it’s used there. They are not suitable for edge-case testing, but are very good at exploring the domain.

There is nothing special in unit tests for applications that are using Yesod – they are just plain Haskell UTs, ignoring the whole Yesod thing.

Next group of tests are server tests – ones that use backend. They should be ran against a fairly-complete app, with backend database set up (preferably on the same host), but without connection to external services or full deployment (proxies, load balancers etc.). It should mostly test reactions on API calls – in most cases you will not want to test the HTML page but rather some JSON or XML responses (testing HTML is much harder). Yesod provides such tests (called integeration tests there, but this name is often used in many contexts) in a helper library, yesod-test. Examples of such tests together with Hspec framework are included in the default scaffolding in test/Handler directory. As you can see, these are quite like HTTP requests, except that they don’t really go through any port, and the communication happens inside a single binary. I really recommend writing this kind of tests – they give a (nearly) end-to-end view on the processing, and are still quite efficient (single binary with occassional DB access). One more thing about the database: beware. While you’ll probably want to use it in these tests, you have to be sure which applications communicate directly with the database. I don’t mean “the same instance of database as your test database”, as I’m sure that you’ll have a special database for tests, preferably set up from scratch on each test run. What I mean is that it’s quite common that more than one application communicate with the same database – for example, for market analysis. That’s an important point, because if you use a shared database, database is also one of your interfaces and you should treat it with the same care as you treat your other interfaces.

There are two types of interface (UI) tests – first one is testing for view – as in Jest, a library for testing React views – and the second type is testing for functionality – as in Selenium. I’m focusing on tools for web projects here, because Yesod is a web framework, but same types are important in pretty much any area, including mobile and desktop applications. These types of tests are probably responsible for the most hatred from the development teams to testing of all tools. That is because both these types are brittle, and small, seemingly not connected changes can break them. These changes include moving the button a few pixels left or right, changing the tone of the background, removing one or two nested divs. Of course, properly written tests will yield more reasonable results (if you’re using Selenium, check out the Page Object pattern), but still, they’re much less change-tolerant than the other types. Additionally, they are not yet fully mature – despite the fact that Selenium is there for a few years already, the driver for Firefox is still not ready (I know that it was broken by Firefox 48 and that geckodriver is not responsibility of Selenium team – still, lack of driver for one of the top browsers signals immaturity of tooling as a whole), so you may encouter quite a few glitches. Nevertheless, I really recommend to implement tests for some basic functionalities of the app. In the beginning it might seem that manual clicking through the app is faster, but amount of manual clicking never ceases to increase, and our patience does – and the quality of testing suffers. Of course, I’m not asking you to implement every single detail in UI test – but at least check basic features – that checkboxes work, that submit buttons cause submits and that data is available in the UI after its submission. Oh, and there are Selenium bindings for Haskell. For web tests your setup should be similar to the one created for server tests, while for view tests it may be simpler – for example as simple as four UT setup.

The last type of tests is arguably the most complex one and most IT projects don’t have them. The are run in the actual production environment (with the exception for no serving of real clients yet) and/or its clone. Their purpose is to guarantee that deployment was done properly, communication with external services is fine and generally the application is ready to start serving real clients. This is no longer time for checking the functionality – this should have been done earlier – only a few basic scenarios are executed, mostly to guarantee that interfaces between system components (services, external world and things like OS) are working fine. Static typing help here as well – perhaps Yesod is not the best example, but Servant is kinda famous for generating type-safe WebAPIs. Still, we have to check that services were built in compatible versions, ports are not blocked etc. Altogether – this step is more of a job for a DevOps guy and simplifies rather operations than development, but hey – in your startup you’ll have to write everything on your own and deal with the administration as well, so you’ll better get to know it!

By the way, that’s precisely what we’re going to deal with in the next post – setting up an automated deployment routine to provide us a fully automated continous deployment pipeline. The whole task probably won’t fit in a single post, but hey – let’s see.

Stay tuned!

JSON API in Yesod

September 6, 2016 Web frameworks, Yesod No comments

We’ve managed to implement a full set of CRUD operations on our Project type. Still, our app is definitely not perfect – for example, in the previous post we’ve implemented DELETE handler as Html Handler. That’s not exactly fine, since browsers generally use only GET and POST – other methods (such as DELETE) are used either by web services or by AJAX calls. We used it as AJAX call, and that’s why we can’t exactly use typical redirection, and instead we redirected the user by hardcoded link. This lead to races and projects which were just deleted were sometimes visible. In this post we’ll deal with this problem.

We’re going to remove the hardcoded link and instead redirect user to link returned from API call, after results are returned. To do this, we need to make several changes:

  1. add a Handler for JSON DELETE requests
  2. remove redirection from button
  3. add redirection to AJAX handler
  4. change request to accept application/json header

First one is critical for us, so let’s start with it. We’ll provide only DELETE method – this way we’ll have something to implement when discussing high-level testing.
Right now we want to provide only JSON responses. Since Yesod uses Aeson library under the hood for JSON handling, its types will also appear in the handler (Aeson uses Value type to denote JSON). New implementation of deleteProjectR looks like this:

deleteProjectR :: ProjectId -> Handler TypedContent
deleteProjectR projectId = selectRep $ do
    provideRep $ do
      _ <- runDB $ delete projectId
      renderUrl <- getUrlRender
      returnJson $ object ["target" .= (renderUrl ProjectsR)]

There are quite a few new elements in here! First one is the signature – Handler TypedContent. TypedContent means that Yesod will check headers and verify whether it can provide a representation required by the client (by default it’s not checked). For example, if client requests application/xml, but we can only provide application/json, a 406 (Not Acceptable) error will be returned. This data type check is done by selectRep function, basing on provideRep calls. There is a little trick here – actual delete is performed in provideRep call. That’s not perfect, as it has nothing to do with the representation, and we would prefer to execute the action always if we can provide the return type. For now it’s not a big deal since we have just one representation, but this can lead to problems (code duplication mostly) later on, when we’ll have many representations. Creating the JSON is done in a bit simplistic way (to make it totally clean we should define a data type, a ToJson instance etc.), but doing it in more sophisticated way seems like an overkill.

Anyway, we’ve done our job on the server, and everything still works – that’s because jQuery AJAX calls accept all possible responses (Accept: */* header). We want to change it, since we’ll be only able to handle JSON responses – thus our templates/project.julius will change to:

jQuery("#delete-project").on("click", function() {
  jQuery.ajax("@{ProjectR projectId}", {
    method: "DELETE",
    headers: { Accept: "application/json; charset=utf-8" }
  }).done(function(response) {
    window.location.replace(response.target);
  });
});

This will redirect you to proper page each time after deletion, thus there will be no race condition. Only thing left is to change the hyperlink to actual button:

<button href=@{ProjectsR} .btn .btn-danger #delete-project>Delete

in project.hamlet. And it’s done!

We’ve implemented our first JSON API. It might not be very impressive, but works well – at least better than the previous solution, which had a built-in race condition.
That’s it for today! Since we’ve already implemented quite a lot of stuff, we would like to be sure that it keeps working after each change. This is what the next post will focus on – testing environment preparation and testing the application. This will be just a short instruction of how to manually prepare a single environment for testing – automatically generating and deploying such environments is a much harder topic and we won’t be focusing on it now. Perhaps later, who knows? Maybe we’ll even have a series on environment automation!

Stay tuned!

Finishing the CRUD

September 5, 2016 Databases, sqlite, Web frameworks, Yesod No comments

Today we’re going to implement the last of CRUD (Create-Read-Update-Delete) operations on our projects. We already know most of the process, so let’s dive into the code!

First, add DELETE method to /project/#Int route (it’ll look like this: /project/#Int ProjectR GET DELETE. Then, second step – handler. In Handler/Project.hs let’s implement:

deleteProjectR :: Int -> Handler Html
deleteProjectR projectId = do
  _ <- runDB $ deleteBy $ UID projectId
  redirect ProjectsR

and handling is done! Now, how about adding a trigger? In templates/project.hamlet we’ll add two buttons – one for project edition, and one for deletion.
That’s also fairly easy, just add:

  <div>
    <a href=@{ProjectEditR projectId} role="button" .btn .btn-primary>Edit
    <a href=@{ProjectsR} role="button" .btn .btn-danger #delete-project-#{projectId}>Delete

to the end of file. Now, while routing to edition works straight away, that’s not true in case of delete – we need to add a custom JS handler to it. In Yesod this is typically done by using Julius template language – which is simply JavaScript with some variable interpolation. Luckily for us, we don’t have to use pure JavaScript – Yesod in the scaffolding embeds jQuery on the page. While we could live without it, I doubt that many pages will be implemented without this library, so we’ll use it. Of course, it’s not as rich as React or Angular when it comes to user interfaces, but let’s face it – we just need a simple hook here. And it’s sufficient to write:

jQuery("#delete-project-#{rawJS $ show projectId}").on("click", function() {
  jQuery.ajax("@{ProjectR projectId}", { method: "DELETE" });
})

This is just your plain old JavaScript, with one detail – variable interpolation (#{rawJS $ show projectId}). As you can see, it’s a bit different than in Hamlet – the rawJS call is quite important here. If we didn’t use it, the default interpolation would come in – and it uses JSON encoding, so it wouldn’t work (in this exact setup – it’s of course possible to make it work with JSON!).

Note a trick we’ve done here – to keep every Handler a Handler Html, we’ve implemented redirection separately from deletion (deletion is sent on button click, while redirection happens on link). Note that this means bad design and code duplication – we did it purely to avoid API calls requiring JSON/XML responses. We’ll deal with them soon, but for now – let’s avoid them. There is one more problem with this code – it might occassionally display elements that were just deleted in projects list – this is because requests are not ordered, so redirection may be handled before deletion. In extreme case, deletion might not be sent properly. We’ll deal with all these problems in the next post, about API – for now, we can live with it.

For some reason integration with Julius is not as smooth as with Hamlet – several times stack didn’t catch my changes and I had to rebuild manually (reset stack command).

There are two more simple UI changes I want to make: add “back” button to edit page and “add new” button to main projects list.
Both these changes seem quite straightforward:

<a role="button" href=@{ProjectR projectId} .btn .btn-default>Back to view

to templates/project-edition.hamlet and

<a role="button" href=@{ProjectEditR newProjectId} .btn .btn-default>Add new project

to templates/projects.hamlet. But there’s a little problem here – we need to generate newProjectId. And it should be as unique as possible. Before we approach this problem, let’s understand why do we actually face it, and how to avoid such problems in the future.

UID field of Project is an artificial field, that doesn’t actually resemble any domain entity. It serves only for our internal purposes, and – in this sense – is a clone of ProjectId provided automatically by Yesod. We don’t have such trouble with ProjectId not only because we don’t use it – if we did, it would be automatically assigned to a unique identifier. So, to simplify our mental model, we actually shoot ourselves in the foot. Oh well, good that it’s such a simple application, it would be much worse if the app was a real server. We’ll fix this issue straight away, since it’ll be much easier that generating a unique identifier.

This adjustment requires quite some changes!

  • config/projectModels – removal of identifier field and UID uniqueness constraint
  • config/routes#Int to #ProjectId in route signatures
  • Handler/Project.hs – signatures, invocation of renderPage (projectId is totally internal now, so shouldn’t be displayed – but is still needed for routes), getBy404 to get404, deleteBy to delete and page selection – this one might be tricky, so here’s my solution:
    selectPage :: ProjectId -> Widget
    selectPage projectId = do
      project <- handlerToWidget $ runDB $ get404 projectId
      renderPage projectId project
    
  • Handler/Projects.hs – signatures and removal of mapping on fetched projects
  • Handler/ProjectEdit.hs – form (no identifier anymore!), signatures. And upserting – as you can see, upserting doesn’t take ProjectId as argument, therefore – by default – would simply add each project as a new one. To prevent this, we’ll have to implement two routes with two actions – insert for new ones and update for existing ones (using solution proposed on StackOverflow)
  • Database/Projects.hs – we’re actually going to remove this file altogether – we can insert projects via web interface, so for now we do not need hardcoded data. We’ll need it again when we get to testing, but it won’t be until next week, so we can wait. Removing this file will also cause us to remove the insertion hack from Application.hs.

Remember abour a runtime change – since we removed a field, automatic migration is not possible, so we need to perform it manually. The easiest way is to simply wipe out all the data and insert it later on – for now it’s good enough. It won’t be good enough when we get to testing, but we still have some time for fun before that happens.

These are mostly simple changes, but remember – if you have any trouble with implementing it, you can check out working code from GitHub. We’re focus on Handler/ProjectEdit.hs, since it changes quite vastly., and some of changes are not obvious.

First of all, we export four routes now: postProjectEditIdR, getProjectEditIdR, postProjectEditNoIdR, getProjectEditNoIdR. They are just a thin wrapper over postProjectEditR, which has a new signature, Maybe ProjectId -> Handler Html. Next change is in widget files – since we have one page, and two possible sources (new project/project edition), we need to support this in routes. To make it easier, we’ll introduce intermediate variables, defined as follows:

backRoute = maybe ProjectsR ProjectR projectId
postRoute = maybe ProjectEditNoIdR ProjectEditIdR projectId

Database fetch becomes quite tricky as well – the following form works:

postProjectEditR :: Maybe ProjectId -> Handler Html
postProjectEditR projectId = do
  project <- (runDB . get) `mapM` projectId
  renderForm projectId $ join project

`join` is used to flatten `Maybe`s (we have a `Maybe (Maybe Project)`, since we can have no id – first maybe – or database may contain no project – hence second).
Remember about modifying upsert call! Now we either update or insert, which boils down to:

updateCall = maybe insert (\id val -> repsert id val >> return id) projectId

this lambda expression doesn’t look nice, but repsert (replace, insert if doesn’t exist) doesn’t return anything by default, and we need the id here.

That’s it for today! We did a lot of good job – cleaned up several hacks, adjusted type signatures, added possibility to delete entities. The app is pretty much complete when it comes to basic functionality. In the next post we’ll clean up today’s DELETE implementation with the use of AJAX calls and HTTP API.

Stay tuned!

Get the data in

September 4, 2016 Databases, Web frameworks, Yesod No comments

We managed to successfully generate form and redirect the user, but that’s still not enough – the data on the server is still static, as POSTs do not cause database to be updated.

Well, today we’re going to deal with this problem. Since we’re using same logic for both adding and updating new items, we’re gonna use upsert function. It’s a function that does exactly what’s necessary – if matching item exists, updates it, if it doesn’t exist – creates it. It fails (throws an exception) if there uniqueness constraints are broken, but luckily – that won’t be the case, as we have only a single unique constraint (UID). Luckily for us, Persistent offers upsert function. This function takes two arguments – first is a PersistEntity(Project), second is the list of updates to perform if record already exists. Default value (for empty list) is to replace the record, which is perfectly fine for us.

The code is simple – in Handler/ProjectEdit.hs change handling of FormSuccess to

FormSuccess project -> do
   (Entity upsertedId upsertedProject) <- runDB $ upsert project []
   redirect $ ProjectR (projectIdentifier upsertedProject)

and that’s it – field will be updated and you’ll be redirected to the view of newly added project. One little trick here is that we use projectIdentifier upsertedProject instead of projectId – this is done on purpose, and is there to handle weird cases properly. As you remember, projectId is taken from route, and projectIdentifier is set in a hidden field. A user with some development knowledge could change the value of the field and submission would go to different id than the actual UID of the project. I admit that it’s not the best design ever, but I also believe it’s good enough for us.

Long story short – we did it! Modifications are now stored to database and user is redirected to page of inserted project. Which is kinda poor right now, as the only information displayed is short name of the project. Let’s modify it and change templates/project.hamlet to:

<div>
  <h1 .page-header> Project ID: #{show projectId}
  <p> Name: #{name}
  <p> Short name: #{shortName}
  <p> Deadline: #{show $ utctDay deadline}

To make it work we also need to add proper definitions to Handler/Project.hs, but it should be a piece of cake for you! If you want some hints, remember that working code for the service we’re writing is available at GitHub.

For full life cycle of projects we still need one more operation – delete. Also, an easier way of adding new projects and editing existing ones would be kinda nice. We’ll solve these problems with buttons, Julius and jQuery next week. Even though it will totally work and be nice and stuff, Julius isn’t really what we want for writing our frontend logic – it’s still your usual JavaScript, just with some variable interpolation. After we deal with the rest of the machinery for our service (and there are not that many left – session, logging, JSON responses, deployment), we’ll refactor Julius frontend into a frontend based on GHCJS.

Next post – deletes and some cleanup – coming next week.

Stay tuned!

Generate the form

September 3, 2016 Web frameworks, Yesod No comments

Sorry for the delay of this page – last week was quite a hard time and this post took much longer than I thought. To make up for it, this week will get two posts – first today and second one tomorrow.

As you probably remember, last time we managed to set up database connection and fetch projects from it. Still, we didn’t have an option to insert data – all our data was preset from a hardcoded file. Well, good news – today we’re going to remove this obstacle.

Right now we’re going to do: add a new route – project/[id]/edit for project data edition – we’ll create a formular and a handling routine.

First of all, let’s start with the route. That’s pretty straightforward and you probably know the right syntax:

/project/#Int/edit ProjectEditR GET POST

in config/routes. A new thing here is that we handle POST as well as GET (no DELETE yet though!), but it doesn’t make a big difference. We just have to provide one more function – postProjectEditR in our handler. So let’s do it now – create a Handler/ProjectEdit.hs and include it in Application.hs and .cabal file.

Now we’re going to write the handler – that’s the core of our today’s concept, so let’s start with a little introduction.

There are three types of forms in Yesod – applicative forms, monadic forms and input forms. Applicative ones are the most common, and ones that we’re going to deal with today. Monadic ones are used in case of non-standard view, and input ones are not generated, but only received (e.g. because of dynamic fields). Applicative forms are generally created by composing preconfigured fields. Let’s take a look on a more concrete example – our Project with four fields – identifier, name, shortName and deadline. While changing identifier might seem a bit weird (it’s in URL after all!), we’re not going to care about it – it’s the forms that are interesting today after all, not the semantics of project addition, right?

We’ll start with creating the form. Type signature will be a little weird – Int -> Maybe Project -> AForm Handler Project. That’s a little unintuitive, but our route allows for accessing UIDs without projects, and if the project already exists, we want to fill in rest of the fields.

We’re gonna start with the easy part – the Hamlet template for the form. W’ve already created quite a bunch of Hamlet templates, so it shouldn’t be a big deal. Here’s the code for templates/project-edition.hamlet (by the way, if you’re wondering how to change templates directory in Yesod – you can’t, it’s hardcoded):


<div .jumbotron>

<h2> Project edition

<form method=post action=@{ProjectEditR projectId} enctype=#{enctype}>
    ^{formWidget}

pretty simple, eh? We just add a master block, a heading and form declaration (with encoding and target route – be careful with the indentation – it’s important that formWidget is under form) and that’s all – well, maybe except the formWidget, which we still have to create. We should do it now, but, unfortunately, it’s not that simple. Yesod uses runFormPost function to both generate a form and evaluate input data against it. It has quite an impressive type signature, but the important thing is the result – it’s m ((FormResult a, xml), Enctype). FormResult a is the parsed result, information that no data was provided or a list of error messages, while xml is the formWidget we’re looking for. Enctype is not really interesting – it is the encoding required by form (UrlEncoded or Multipart). It’s argument is a function, that tranforms Markup(roughly Html) to MForm (a formular).

Before diving into code, let’s recap what we’re going to do:

  1. create a POST/GET handler (one for both methods)
  2. fetch project from database, if it already exists
  3. generate form with prefilled fields (in case of existing project)
  4. after submission, save the form to database

Quite a lot of work for a single post, right? We’d better get started straight ahead!
Let’s start with the POST handler:

postProjectEditR :: Int -> Handler Html
postProjectEditR projectId =  do
  project <- runDB $ getBy $ UID projectId renderForm $ (\(Entity _ proj) -> proj) `fmap` project

That’s fairly straightforward and similar to what we’ve done in Handler/Project.hs. Perhaps the only interesting part is using the fact that Maybe is a Functor, so we can use fmap on it (it’ll be executed on Just value, Nothing will be ignored). Well, since the first part is already done, let’s go to the rendering part!

renderForm :: Maybe Project -> Handler Html
renderForm projectId projectEntry = do
  ((result, formWidget), enctype) <- runFormPost (projectForm projectId projectEntry) case result of FormSuccess project -> redirect $ ProjectR (projectIdentifier project)
    _ -> defaultLayout $ do
      app <- getYesod
      setTitle $ (toHtml $ (appName app)) ++ ": editing projects"
      $(widgetFile "project-edition")
      $(widgetFile "back-to-projects")

Now, this piece of code is much more interesting – first of all, it uses the actual form, generated by projectForm projectId projectEntry. We didn’t write this function yet, so it’s more of a stub for the future. Next interesting part is handling of successfully created Project – here we simply redirect to view page. This means that we don’t actually insert anything to database – we’re gonna deal with the inserting later on. And the rest is displaying the form (we’ve created the Hamlet template in the beginning).

Now, before we get to the actual form, there is one more level of indirection that I’d like to introduce:

projectForm :: Int -> Maybe Project -> Html -> MForm Handler (FormResult Project, Widget)
projectForm projectId project = renderBootstrap3 BootstrapBasicForm $ projectAForm projectId project

I want to introduce it, since it’s quite independent from the form creation, but is the point at which the layout is decided (the form’s form). There are a few interesting things here – first of all, it returns a MForm (monadic form version), and creates it from applicative version of form (AForm). Next, it performs the form conversion to Bootstrap mechanisms – namely BootstrapBasicForm. There are three types of Bootstrap form layouts, and this one is simplest – label above input field. Looks good enough for our purposes, so let’s finally get to creating forms!

Here’s the code:

projectAForm :: Int -> Maybe Project -> AForm Handler Project
projectAForm projectId project = Project
    <$> areq hiddenField identifierConfig (pure projectId)
    <*> areq textField nameConfig (projectName <$> project)
    <*> areq textField shortNameConfig (projectShortName <$> project)
    <*> areq utcDayField timeFieldConfig (projectDeadline <$> project)
    <* bootstrapSubmit ("Modify" :: BootstrapSubmit Text)
    where
      identifierConfig = bfs ("" :: Text)
      nameConfig = withPlaceholder "Project name" $ bfs ("Project name" :: Text)
      shortNameConfig = withPlaceholder "Short project name" $ bfs ("Short project name" :: Text)
      timeFieldConfig = bfs ("Project deadline" :: Text)

Lots of code, eh? But it’s mostly simple, so it shouldn’t be a big deal. First we declare that we’re gonna create a Project, and then list it’s fields. In our case all the fields are required (areq – optional are added by using aopt). Fields are added by using <*> operator. First areq argument is type of field (e.g., textField), second – field configuration (in our case labels, but we can also set tooltips or ids) and third – default value. We take most default values out of database project, except identifier – we know it for sure, so it’s taken from URL (as an argument). bfs call in all settings is used to underline the fact that we use Bootstrap styles, and it’s argument will be used as a label for field. There is one little quirk here – currently Bootstrap forms in Yesod don’t handle hidden fields very well, and leave some space for it (namely, space for the label). This might be fixed when a GitHub issue is resolved, but it’s quite old already, and it doesn’t work yet. A possible workaround is to add this field to form after its creation, but it’s not a nice solution, and we’re just gonna live with the current state for now.

We’re almost done – there is just one thing left to display the form. Namely – utcDayField does not exist in Yesod. But fret not! Yesod has a built-in Day field, which is used for dates. We just need to transform it so that using the same field will yield a different data type as output. Luckily, Yesod provides a function to transform one field to another, and it has (quite unintuitive) name checkMMap. Our defintion of utcDayField looks like this:

utcDayField = checkMMap (return . Right . toUTCTime :: (Day -> Handler (Either Text UTCTime))) utctDay dayField
  where
  toUTCTime x = UTCTime x (secondsToDiffTime 0)

Looks a bit magical, I agree. Basically we need to provide two functions: one to transform Day to UTCTime (to inject data to our code), and second, to transform UTCTime to Day (to display default value properly). This is done be toUTCTime (defined) and utctDay (built-in). Rest of the definition (return . Right . and type signature) serves mostly to feed the type system.

And we’re done! The form is generated and user can display it easily. A nice bonus is that Yesod-generated forms automatically provide tokens that protect us from CSRF attacks.

Remember to add also handler for GET requests (getProjectEditR = postProjectEditR is a sufficient implementation) and required imports: Yesod.Form.Bootstrap3 and Data.Time.Clock).

That’s the end of today’s post. We did a lot of things – accessed database to fetch a – possibly existing – project, generated a form and filled it with default values. We didn’t manage to insert the data to database yet – we’re going to do this in the next post, tomorrow.

Stay tuned!

Database, configuration and cleanup

August 16, 2016 Databases, sqlite, Web frameworks, Yesod No comments

We already have a database set up, some example data inserted and we’re using it in part of our application. Cool. Now it is time to discuss a little more about configuration of the database.
You might have spotted that we’re using runSqlPool instead of runSqlConn or even runSqlite – that is because – obviously – Yesod uses a pool of database connections. While it might not seem critical, it’s quite important for the configuration. First of all, pool size has to be defined. By default the scaffolding takes all startup parameters from YAML file – config/settings.yml (config/test-settings.yml for test configuration overrides). It’s loaded in Settings.hs, so if you ever need to add configuration options (and I guarantee that you will need to), do it there.

Database configuration is near the end of the file:

database:
  # See config/test-settings.yml for an override during tests
  database: "_env:SQLITE_DATABASE:civil-project.sqlite3"
  poolsize: "_env:SQLITE_POOLSIZE:10"

it has a quite convenient syntax, that allows deployment without modification of configuration files – if an environment variable with a given name (here: SQLITE_DATABASE and SQLITE_POOLSIZE) exists, it is used as the value, otherwise the default (civil-project.sqlite3 and 10) is taken. Now, while analysis of pool size have no sense here, since that’s a parameter used mostly for performance reasons, the default location of the database is quite unfortunate. It leaves us with stuff between consecutive application runs, require to manage the schema during development etc. Or manually delete database file each time, which is not that bad, but not perfect either, especially that it lies in the middle of source.

A perfect solution would be to run database in memory. This is possible, and not very hard – theoretically it should be sufficient to change configuration option to database: "_env:SQLITE_DATABASE:':memory'". Not obvious change, as it requires additional apostrophes, but not hard as well. And that’s enough to run SQLite database in memory. That would solve a lot of problems with the schema – database would be created from scratch each time. We’d have to keep example data somewhere in source, but we’ll need that for test reasons anyway so that’s no big deal. So, perfect, right?

No.

Unfortunately, there is one issue that causes this great plan to fail – in memory database does not play well with connection pools. Connections from pool are broken when there is no activity, and this causes in memory database to be deleted. At least that’s the scenario described on Yesod’s Google Groups.

So, there are two choices – we can either use a pool and a disk database or a single connection and in memory database. Since we’re now dealing with development issues, not testing, we can live with disk storage (we’ll rethink it when designing our tests). However, to provide some minimal encapsulation, we’re going to create a directory, workspace, and put the database there. Just create the directory and change database location (database: "_env:SQLITE_DATABASE:workspace/civil-project.sqlite3" is the line you might be looking for), remove the old database (or move it to workspace) and that’s it for the database location.

Now let’s do some cleanup in the code. First, routes. In our case, /projects redirects to ProjectsR handler, and /project/[x] to ProjectR handler. That’s not exactly how most web applications behave – in typical case it would be /project and /project/[x] (note lack of plural form in the first one). It’s not a big change, so let’s do it. Now our routes contain:

/static StaticR Static appStatic
/auth   AuthR   Auth   getAuth

/favicon.ico FaviconR GET
/robots.txt RobotsR GET

/ HomeR GET POST

/comments CommentR POST

/project ProjectsR GET
/project/#Int ProjectR GET

I’m not going to get rid of the scaffolding routes yet (/comments, /), but in the future we’re gonna remove them, no worries.
Second thing is a little more complicated – we’re going to show all projects from our database in the main list, not just the ones we have hardcoded (that’s no difference for now, but in the next post we’re gonna explore forms and add some new projects – it’ll make a difference then).
You can start with removing import Database.Project(projects) from Handler/Projects.hs (that’s the easiest part), and then do the magic.
Database actions run in their own monad, which cannot be easily mixed with the one from layout. Therefore the code will complicate quite a bit:

getProjectsR = do
    projects <- runDB $ do
       dbProjects <- selectList [] []
       return $ map entityVal dbProjects
    defaultLayout $ do
        setTitle "Projects"
        $(widgetFile "projects")

As you can see, there is one “master monad” wrapping two smaller ones – one for fetching existing projects from database, the other for generating HTML response. Check it out, it really works!
There are a few things worth noting here – first of all, this will work only for small lists of projects – they are loaded into memory all at once, thus big lists would cause out of memory error. Second is the entityVal function, which extracts value from a database record. You might remember that in Handler/Project.hs we achieved similar functionality by pattern matching to Entity projectId project (exact code was Entity _ project). Both are fine, feel free to use whichever one suits you best.

And that’s it – we’ve managed to use DB in project list as well! Now, since we are already able to read from database, it would be nice to be able to write something. And that is what we’ll be dealing with in the next post – forms and simple data upload.

Stay tuned!

Attaching database to Yesod app

August 15, 2016 Databases, sqlite, Web frameworks, Yesod No comments

Today we’re going to attach a real database to our application and stop using hardcoded list of projects (well, partially – we’ll still use it to populate database on startup). First we need to understand several things – where is the model stored, how to fetch the data, how to perform database migration.

For now we need just a simple feature of fetching project records by their unique identifier – not the one assigned by Persistent (although this would work out-of-the-box), but the <code>identifier</code> field. Luckily, Persistent offers a feature of assigning unique identifiers to fields (not supported in MongoDB) – fields starting with uppercase letter are assumed to create a new index. in our case – add UID identifier to Project definition in Domain/Project.hs. That’s it for the index, now let’s go to fetching – that’s also fairly easy, it’s sufficient to change selectPage implementation to:

selectPage :: Int -> Widget
selectPage projectId = do
  (Entity _ project) <- handlerToWidget $ runDB $ getBy404 $ UID projectId
  renderPage project

And getting is done. We also get 404: NotFound handling for free – if a record is not found in database, 404 is automatically returned and no further processing is needed. The Entity type here might be a little confusing – it means that the value is taken directly from database and that it is an actual database record. Its first field (here omitted) is id assigned automatically to the data (we don’t need it here). So, that’s it, right? Should it already work? Let’s try it out: stack exec -- yesod devel. It compiles, that’s a good sign. Let’s navigate to localhost:3000/project/1. Whoops, is it an Internal Server Error? What has gone wrong?

The error obviously says that project table doesn’t exist in the database. Oh, right. We just defined migration, but did not run it! Application compiled, because we aren’t obliged to run migration – for example, database may be owned by another team or may be used by more than one application – that’s a logic error, which is not typechecked right now in Yesod. Let’s run the migration then. The scaffolding runs migrations in makeFoundation function, in Application.hs file. The function is quite long, but the important part is runLoggingT (runSqlPool (runMigration migrateAll) pool) logFunc. It seems that some migration is already done, what’s going on?

That’s migration for data structures of the scaffolding – users, comments. Where are they defined? If you inspect Model.hs, you’ll find the following code:

share [mkPersist sqlSettings, mkMigrate "migrateAll"]
    $(persistFileWith lowerCaseSettings "config/models")

Apperently that’s also some Template Haskell magic – and entities are defined in config/models.
This file looks quite reasonable:

User
    ident Text
    password Text Maybe
    UniqueUser ident
    deriving Typeable
Email
    email Text
    userId UserId Maybe
    verkey Text Maybe
    UniqueEmail email
Comment json -- Adding "json" causes ToJSON and FromJSON instances to be derived.
    message Text
    userId UserId Maybe
    deriving Eq
    deriving Show

 -- By default this file is used in Model.hs (which is imported by Foundation.hs)

These are simply data definitions, structurally identical to the one we put into Domain/Project.hs. So, have we put our definitions in a wrong file? Not quite. Yesod as a framework is quite composable. We can use structues provided by scaffolding or not use them, it’s not going to blame us for either of these choices.
So theoretically we could just add our definition of Project here and be done with it. If you prefer this way – go ahead, I won’t blame you. I don’t like the idea, because it causes two separate domains to be mixed, and be tough later on. You can do two other things to solve this – either import Domain.Project everywhere where it is needed, or rely somehow on semi-default behavior. I’ve chosen to go for semi-default behavior – extract models to a separate file, but handled the same way the default one is. I’m not going to argue whether this is better or worse than keeping separate Domain.Project – both have their pros and cons. For example, by putting data definitions to separate file which is included in Import.hs, whole application may start to rely on these data structures. This may cause quite a lot of trouble during refactoring later on, even though we have a strong type system to save us from the simplest mistakes. On the other hand, importing Domain/Project.hs in every place is not what you would expect at first. For now I’m going to stay with the scaffolding’s approach, and if it proves hard to maintain – refactor.

Let’s create a config/projectModels file with the content from the quasiquoted part of Domain/Project.hs:

Project
      identifier Int
      name Text
      shortName Text
      deadline UTCTime
      UID identifier
      deriving Show

Now we can remove Domain/Project.hs and all it’s imports – it’ll soon become visible by default (from Import.hs). To make it visible in all (unfortunately) files that import Import.hs add the following call to Model.hs:

share [mkPersist sqlSettings, mkMigrate "migrateProject"]
    $(persistFileWith lowerCaseSettings "config/projectModels")

That’s all nice and fine, but we still don’t have our migration! To add it to application startup add runLoggingT (runSqlPool (runMigration migrateProject) pool) logFunc line to Application.hs, just below runLoggingT (runSqlPool (runMigration migrateAll) pool) logFunc. We could actually remove the latter, but it may be useful later on when learning more Yesod’ish patterns.

You might have guessed by now that mkMigrate string argument is name of function that will be created for migration. That’s quite a common pattern in places where Yesod uses Template Haskell.

In a big web application I would seriously consider either leaving out this pattern or importing everything to avoid code tangling – but I belive that this app will be small enough to ignore this problem – after all our main objective is to learn some Yesod here, isn’t it?

Now, that’s all nice and fine, but now we have 404s on each project read, and actually we’d prefer to read an actual record from the database, right? So we have to populate the database. Today we’ll do it in a brute-force way, but soon we’ll be honing this as well.

For now, it’s sufficient to add _ <- mapM (\p -> runLoggingT (runSqlPool (insertBy p) pool) logFunc) projects to makeFoundation, just after migrations. You might be tempted to use insert instead of insertBy, but this would cause your application to require much more maintenance – namely, removal of the database after each startup (SQLite would return an error when inserting entries with same UID, and error on startup means that whole application needs to be shut down). Of course, such solution is ugly and adds hacks to production code just to handle development needs – still, it’s ok for us now.

Try out the app after changes – functionality is same as before, but now data is fetched straight from database, which means that we can also insert new entries at runtime. We’re going to deal with forms and inserting in near future, but the next post will be again about databases – where is it? Why our list of projects is still a constant?

Stay tuned!

Using Persistent tables

August 10, 2016 Web frameworks, Yesod No comments

Databases are important. We need to keep all kinds of data in our applications – users, workspaces, messages, even things like selected UI theme. Yesod’s typical answer to this problem is Persistent. Persistent is a Haskell library for accessing databases – ranging from SQLite to MongoDB. It provides a type-safe access from Yesod to database and manages database schema and its changes (that’s actually done in runtime, but connection won’t be established without proper schema). Of course, not all migrations are possible to detect automatically – for example renaming a field will not be executed automatically. You can find more details about migrations in the Yesod Book, chapter about Persistent.

Luckily, our case is pretty straightforward – we want to store records for projects. For now we need only current state of the projects, so we’re going to use the usual facilities offered by Persistent. This involves some Template Haskell, but don’t worry, it’s quite straightforward. First we need to define our data type – but in a little special, Persistent-dedicated way. We’re gonna leave our pair-driven implementation and move to more complex data type. Our Project type will consist of a numeric identifier, textual name, short version of name and a deadline. I was quite tempted to leave out the deadline field since it introduces a bit of trouble, but after all – what’s a project without a deadline?

So, let’s create a Domain/Project.hs file with the following content:

module Domain.Project (Project(Project, projectIdentifier, projectName, projectShortName, projectDeadline)) where

import Import

share [mkPersist sqlSettings, mkMigrate "migrateProjects"] [persistLowerCase|
Project
  identifier Int
  name Text
  shortName Text
  deadline UTCTime
  deriving Show
|]

that’s quite dense, so probably requires some explaination. The part between | symbols is the actual data type definition. It is the input to the magic performed by Template Haskell, which results in generating field “accessors” exported in the first line: projectIdentifier, projectName, projectShortName, projectDeadline. You might guess that these are names of fields appended to name of data type and camelCased – there actually is a valid reason to do that – it is really helpful in avoiding name clashes (imagine field id). Actually, there is also a reason why the first field is called identifier and not simply id – Persistent internally creates an index field for each type, thus resulting in a clash. The type of this automatically generated id varies between backend databases – in most SQL-based ones it’s Int, but in MongoDB it’s String. Of course, both are nicely hidden under a type alias [[DatatypeName]]Id.

persistLowerCase is just a way of telling Persistent how to map field names to DB names, so let’s not focus on it. share is more interesting – it’s a helper function that takes a list of function an a quasiquotation as arguments (quasiquotes are these funny expressions strucured as [sth|sth else] – you can read more about them here) and passes the second one as argument for each of elements in the array. In our case these are mkPersist responsible for DB access and mkMigrate responsible for generating new DB schema.

And the last part that might be a little tricky – exports. module Domain.Project (Project(Project, projectIdentifier, projectName, projectShortName, projectDeadline)) – that’s just a way constructors and fields are exported in Haskell, TypeName(TypeConstructor, OtherTypeConstructor, field1, field2...).

Great, we’ve already done the tough job, now we have to clean up. First let’s change Database/Projects.hs. We’ve already prepared our application to interact with a database, but the interaction itself will be the subject of the next post. For now let’s just make it work. Here’s the new content:

module Database.Projects (projects) where
import Import

import Data.Time.Clock
import Domain.Project

time:: Integer -> Integer -> UTCTime
time a b = UTCTime (fromGregorian a 1 1) (secondsToDiffTime b)

projects::[Project]
projects = [Project 1 "Project 1" "P1" $ time 0 0,
  Project 3 "Substantial" "P2"  $ time 1 0,
  Project 5 "What the hell" "WTH"  $ time 100 0,
  Project 10 "The last project" "TLP"  $ time 10 10]

Only tricky thing here is the UTCTime creation. for some reason secondsToDiffTime is not imported by default, thus we need to explicitly add import Data.Time.Clock. This time function is also quite weird, but I guess we can live with that for now – after all we’ll get rid of such syntax in this file in another post (and if we won’t, we’ll refactor it soon).

Minor fixes are also needed in Handler/Project.hs (mostly substituting fst x with projectIdentifier x) and templates/projects.hamlet (same story + pattern matching in $forall). Handler/Projects.hs might also need a little change, namely importing Domain/Project.hs into the scope.

I’ve also removed copyright from the footer. We don’t need it now and it looked awful.

Quite some changes today! Remember that if something doesn’t work for you you can always check out the exact code that I’ve use during writing this post – it’s available at GitHub.

Next episode, in which we’re going to really attach a database to the application comes soon.

Stay tuned!

The foundation datatype

August 8, 2016 Web frameworks, Yesod No comments

This post will introduce some magic that you’ll use on a daily basis when using Yesod. This magic is mostly related to connection with the outside world – while Handler and Widget have IO in their type signatures, there are recommended ways of dealing with it – and this recommended way includes a foundation datatype.

Foundation datatype is a type that is accessible in all your Widget‘s and Handler‘s. In fact, it is even in the signature of your application – in Yesod App, App is your foundation datatype (that’s the name in the default scaffolding, you can change it if you wish to). You can keep anything there – default scaffolding puts there some server settings, connection pools, logger etc., but you can put virtually anything there – it’s just a typical data type.

This time we’re going to use it in a very simple way – to inject application name into the widgets and use it in the title – but on future posts we’ll be using the foundation value in much more sophisticated scenarios, such as database access or configuration. First let’s add the name to our data type – since this is just a tutorial, we’ll add it as a top-level field. So, in Foundation.hs change the definition of data App to

data App = App
    { appSettings    :: AppSettings
    , appStatic      :: Static -- ^ Settings for static file serving.
    , appConnPool    :: ConnectionPool -- ^ Database connection pool.
    , appHttpManager :: Manager
    , appLogger      :: Logger
    , appName        :: Text
    }

Next step, initialization. In Application.hs in code of makeFoundation function add appName <- return "Project M" line. That’s it, you already have your foundation data initialized. A little magic here is performed by the following line: let mkFoundation appConnPool = App {..} – the {..} syntax binds together names that exist in the scope and create a single data record. By the way, you can also use it the other way around: App {..} <- getYesod will bring all the fields to the current scope. I believe it generally clutters the scope and should be avoided. Still, sometimes it can come in handy. getYesod is a wrapped object of the foundation type, which is usually accessed by the syntax mentioned above (app <- getYesod) – yet, it’s a typical Yesod value, so there is no real reason (except maybe convenience) to stick to this method.

In the last step we’re going to change Handler/Project.hs and it’s rendering function. Let’s change the first two lines of renderPage function to:

app <- getYesod
setTitle $ (toHtml $ (appName app)) ++ ": " ++ projectTitle

And that’s it, title on your development server should already change. I’ll change the display to format appName: projectName(projectId), by changing the where clause from projectTitle = (toHtml projectId) ++ (toHtml projectName) to projectTitle = (toHtml projectName) ++ "(" ++ (toHtml projectId) ++ ")".

That’s it for today – soon we’re going to explore the way of using databases with Yesod, but first – in the next post – we’ll have to deal with our data type and make it more useful.

Stay tuned!