Skip to content

alyoanton9/todo-list-servant

Repository files navigation

TODO-list by Servant

Intro

Here you may find TODO-list backend application implemented with Servant, Haskell library for web development.

It has basic CRUD operations, responds with JSON only, uses Persistent as a storage interface, and additionally implements a simple custom logger middleware.

The main goal of this project is to provide a basic example of implementing backend with Servant library, so to make life a bit easier for (future) Haskell web developers.

This code complements the talk "How to Choose a Haskell Web Framework" I presented at Haskell eXchange 2022.

In this talk, I show how some of Haskell web tools approach web development. In particular, there are 3 of them — Servant, Yesod and IHP.

There are also corresponding Yesod and IHP TODO-list implementations.

Check out the presentation slides and the talk recording, and contact me if you have any questions 🙂

API

As application has only basic CRUD operations, here is the API

  • GET /api/task — get all tasks
  • POST /api/task — create new task
  • GET /api/task/{id} — get existing task by id
  • PUT /api/task/{id} — update existing task by id
  • DELETE /api/task/{id} — delete existing task by id

Request & response examples

We use curl to demonstrate interaction with API

> curl -X GET http://localhost:4000/api/task
[]

> curl -X POST http://localhost:4000/api/task -H "Content-Type: application/json" -d '{"content": "wake up"}'
{"content":"wake up","id":1}

> curl -X POST http://localhost:4000/api/task -H "Content-Type: application/json" -d '{"content": "drink coffee"}'
{"content":"drink coffee","id":2}

> curl -X PUT http://localhost:4000/api/task/2 -H "Content-Type: application/json" -d '{"content": "drink mooore coffee"}'
{"content":"drink mooore coffee","id":2}

> curl -X GET http://localhost:4000/api/task
[{"content":"wake up","id":1},{"content":"drink mooore coffee","id":2}]

> curl -X GET http://localhost:4000/api/task/2
{"content":"drink mooore coffee","id":2}

> curl -X GET http://localhost:4000/api/task/5


> curl -X DELETE http://localhost:4000/api/task/1
{"content":"wake up","id":1}

> curl -X GET http://localhost:4000/api/task
[{"content":"drink mooore coffee","id":2}]

Custom logger middleware

Simple logger here just extracts request’s URL path and logs it with "Info" verbosity level.

For example,

[Info] url-path=api/task/5
[Info] url-path=api/task/
[Info] url-path=api/task
[Info] url-path=api/task/8/
[Info] url-path=api/task/3
[Info] url-path=/
[Info] url-path=api/task

Prerequisites

Run

Firstly, you need to configure a connection string to connect to your database. You may refer to the PostgreSQL docs for this.

In this example, the following connection string is used

connectionStr = "host=localhost dbname=todolist-servant user=postgres password=postgres port=5432"

Which means that the local todolist-servant postgres database is accessed via 5432 port.

Make sure that user and database exist before running the app.

Then, run the app

> stack run
Migrating: CREATe TABLE "task"("id" SERIAL8  PRIMARY KEY UNIQUE,"content" VARCHAR NOT NULL)
[Debug#SQL] CREATe TABLE "task"("id" SERIAL8  PRIMARY KEY UNIQUE,"content" VARCHAR NOT NULL); []
...

Hope you'll find it helpful 💙

Releases

No releases published

Packages

No packages published