RealWorld example with Haskell Yesod
Tags: haskell, yesod, rest, example
Published: 2018-08-16 23:37:05

---
title: RealWorld example with Haskell Yesod
published: true
tags: haskell, yesod, rest, example
canonical_url: 
---

This is an overview of an [example implementation](https://github.com/tzemanovic/haskell-yesod-realworld-example-app) of [the RealWorld](https://realworld.io/) backend built using the powerful [Yesod framework](https://www.yesodweb.com/) written in Haskell.

This project is essentially a RESTful API to a database and even though Yesod can do much more than that, you still get a lot of nice things that help along the way. For example, Yesod comes with some helper commands for common tasks (e.g. you can add a new handler using `yesod add-handler`) and you can start a new project using one of the [stack templates](https://docs.haskellstack.org/en/stable/GUIDE/#templates). I’ve started this project with `stack new yesod-sqlite` which scaffolded application with SQLite database connection, whose schema is created from [persistent entity file](https://github.com/tzemanovic/haskell-yesod-realworld-example-app/blob/8411fa8a2ae8c2061323e58eaedd611186cf1394/app/config/models). The scaffolded project is setup with:

* development server setup using ghcid with automatic rebuild and fast reloads
* [hpack](https://hackage.haskell.org/package/hpack) for a nicer alternative to the Cabal package format
* behaviour specification using [hspec](https://hackage.haskell.org/package/hspec)
* fast and scalable logging using [fast-logger](https://hackage.haskell.org/package/fast-logger) for requests and database queries
* log functions from [monad-logger](https://hackage.haskell.org/package/monad-logger) that includes source code location in the log entries
* the fast [Warp](https://hackage.haskell.org/package/warp) web server
* [classy-prelude](https://hackage.haskell.org/package/classy-prelude) as an alternative prelude that removes all partial functions
* [persistent](https://hackage.haskell.org/package/persistent) for type-safe database-agnostic data modelling and querying with automatic migrations in development
* [aeson](https://hackage.haskell.org/package/aeson) for fast JSON parsing and encoding 
* [keter](https://hackage.haskell.org/package/keter) deployment system

If you want to learn more about Yesod, you can read the excellent [Developing Web Applications with Haskell and Yesod](https://www.yesodweb.com/book) for free. Some other dependencies used in this project are:

* [esqueleto](https://hackage.haskell.org/package/esqueleto) - type-safe EDSL for SQL queries on persistent backends
* [forma](https://hackage.haskell.org/package/forma) - parse and validate form input
* [jwt](https://hackage.haskell.org/package/jwt) - JSON Web Token (JWT) decoding and encoding 
* [weeder](https://hackage.haskell.org/package/weeder) - to detect dead code

## Project structure

```bash
app
├── app
├── package.yaml
│   ├── main.hs                     "The main entry point for production build."
│   ├── devel.hs                    "The main for development server."
│   └── DevelMain.hs                "The main for running inside GHCi."
├── config
│   ├── models                      "Persistent entity file with the database schema declaration."
│   ├── routes                      "Routes declaration for our RESTful API."
│   ├── settings.yml                "App runtime settings."
│   └── test-settings.yml           "Settings overrides for tests."
├── src
│   ├── Application.hs              "Loads the settings to initalize the app with a HTTP manager,"
│   │                               "logger and database connection pool."
│   │
│   ├── Foundation.hs               "Declares the foundation 'App' datatype which is accessible"
│   │                               "from every handler, type for routes loaded from `config/routes`"
│   │                               "and authentication requirements for each route."
│   │
│   ├── Settings.hs                 "Declares and loads the app settings, which can be loaded from"
│   │                               "various sources."
│   │
│   ├── Import.hs                   "Commonly used module imports grouped for convenience."
│   ├── Model.hs                    "Generates types for models loaded from `config/models`."
│   ├── Database.hs                 "Database queries."
│   ├── Pagination.hs
│   ├── Handler                     "Handlers for the RESTful API."
│   │   ├── Articles.hs
│   │   ├── Profiles.hs
│   │   └── User.hs
│   ├── Database                    "Helpers for dealing with database."
│   │   └── Persist
│   │       ├── Extended.hs
│   │       └── Types
│   │           ├── Email           "Persistent field type for email, which is"
│   │           │   └── Internal.hs "stored in a case-insensitive string."
│   │           ├── Email.hs
│   │           ├── Password        "Persistent field type for password,"
│   │           │   └── Internal.hs "stored as a hash."
│   │           └── Password.hs
│   ├── Auth                        "Authentication using JWT token."
│   │   └── JWT.hs
│   └── Web                         "User input validation."
│       └── Forma
│           └── Extended.hs
├── test                            "The specs for user and profiles handlers."
│   ├── Handler
│   │   ├── ProfilesSpec.hs
│   │   └── UserSpec.hs
│   ├── Spec.hs
│   └── TestImport.hs
```

## Some notes

The handlers are implemented according to the [API spec](https://github.com/gothinkster/realworld/tree/master/api):

* The `Profiles` module is the most simple one with handlers using persistent queries
* The `User` handlers deal with user input that is parsed and validated using the forma library
* The `Articles` handlers contain more complex queries and pagination for the article feed. Because their queries deal with multiple tables, I reached out to the esqueleto library, which provides a nice eDSL (a SQL language embedded in Haskell) for querying the database.