Showing with 313 additions and 2,123 deletions.
  1. +2 −0 cabal.project
  2. +14 −11 deploy.sh
  3. +13 −3 home.md
  4. +0 −6 pages/tips.md
  5. +157 −0 posts/2017-03-03-servant-and-db.markdown
  6. +124 −0 posts/2018-06-19-servant-0.14-released.markdown
  7. +0 −7 site.hs
  8. +3 −3 templates/default.html
  9. +0 −309 tutorial/0.4/api-type.lhs
  10. +0 −138 tutorial/0.4/client.lhs
  11. +0 −227 tutorial/0.4/docs.lhs
  12. +0 −175 tutorial/0.4/javascript.lhs
  13. +0 −1,176 tutorial/0.4/server.lhs
  14. +0 −68 tutorial/index.md
@@ -0,0 +1,2 @@
packages: .
with-compiler: ghc-8.4.3
@@ -1,24 +1,27 @@
XDG_CACHE_HOME=${XDG_CACHE_HOME:-$HOME/.cache}
SERVANT_WWW="$XDG_CACHE_HOME/haskell-servant-github-io"

REPO_URL="git@github.com:haskell-servant/haskell-servant.github.io"
SERVANT_WWW="$HOME/.servant-www"
SITE="$PWD/_site"
CURRDIR="$PWD"
BIN="dist/build/site/site"
COMMIT=`git rev-parse HEAD`
MSG="Built from $COMMIT"
COMMIT="$(git rev-parse HEAD)"

set -o errexit

if [ ! -d $SERVANT_WWW ]; then
git clone $REPO_URL $HOME/.servant-www
# Build locally
cabal new-run -w ghc-8.4.3 site build

# Clone dir
if [ ! -d "$SERVANT_WWW" ]; then
git clone "$REPO_URL" "$SERVANT_WWW"
echo "Created directory $SERVANT_WWW"
fi

cd $SERVANT_WWW

cd "$SERVANT_WWW"
git checkout master
git rm -r ./*
cp -R $SITE/* ./
cp -R "$SITE"/* ./
git add ./**
git commit -m "Built from $COMMIT"
git push origin master
echo $MSG
cd $CURRDIR
echo "Build from $COMMIT"
16 home.md
@@ -2,18 +2,28 @@
title: Home
---

<p class="notice">The main documentation for *servant* can now be found here:
[haskell-servant.readthedocs.org](http://haskell-servant.readthedocs.org/)
</p>
<emph>servant</emph> is a set of packages for declaring web APIs at the
type-level and then using those API specifications to:

- write servers (this part of servant can be considered a web framework),
- obtain client functions (in haskell),
- generate client functions for other programming languages,
- generate documentation for your web applications
- and more...

All in a type-safe manner.

# Tutorials and Blog Posts

- [Paper](http://www.andres-loeh.de/Servant/servant-wgp.pdf) for a more technical introduction
- [Official tutorial](https://haskell-servant.readthedocs.io/en/stable/tutorial/index.html)
- [Cookbook](https://haskell-servant.readthedocs.io/en/stable/cookbook/index.html)
- [Extending servant](/extending.html)
- [Hackage API client in 5 minutes](/client-in-5-minutes.html)
- [Developing a servant application with Halcyon](https://halcyon.sh/tutorial/)
- [Type-Safe Microservices in Haskell with Servant](https://github.com/k-bx/owlcloud)
- [Type-safe web services in Haskell with servant](http://taylor.fausak.me/2015/08/23/type-safe-web-services-in-haskell-with-servant/)
- [Servant, Type Families, and Type-level Everything](http://www.arow.info/blog/posts/2015-07-10-servant-intro.html)
- [Combining Servant With Persistent](http://www.parsonsmatt.org/2015/06/07/servant-persistent.html)
- [Implementing a minimal version of haskell-servant](https://www.well-typed.com/blog/2015/11/implementing-a-minimal-version-of-haskell-servant/)
- See [the talks](/talks.html)

This file was deleted.

@@ -0,0 +1,157 @@
---
title: Passing a DB connection to handlers in Servant
author: Oleg Grenrus
tags: servant
---

This post is originally published in http://oleg.fi/gists/posts/2017-03-03-servant-and-db.html. This version is updated to use `hoistServer`.

This write-up is motivated by discussion in
[servant/#704 issue](https://github.com/haskell-servant/servant/issues/704).
I try to summarize the main points.


As this is a literate haskell file, we'll need to do a small prelude dance:
```haskell
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators #-}
import Data.Pool (Pool, withResource)
import Data.Text (Text)
import Control.Monad.Reader
import Control.Monad.Base
import Control.Monad.Trans.Control
import Database.PostgreSQL.Simple (Connection)
import Log
import Servant
import qualified Control.Category
-- | Needed for 'MonadLog (LogT Handler)' instance
instance MonadTime Handler where
currentTime = liftIO currentTime
```

The problem
-----------

The issue started as instance XY-problem:

- **Y**: Docs explaining how to actually create a full combinator (ex. one to create/store a DB connection)
- **X**: How to pass a db connection to the handlers.

I won't answer to the **Y**, how to write combinators is different topic (have to write about that later).
Let's see how to deal with **X**, by implementing a small Cat CR(UD) API:
```haskell
-- we should have proper data/newtypes, but then we'll need to write instances.
-- we'll try to keep a boilerplate at the minimum in this example.
type Cat = Text
type CatName = Text
type API = "cat" :> Capture "name" CatName :> Put '[JSON] Cat -- create
:<|> "cat" :> Capture "name" CatName :> Get '[JSON] Cat -- read
api :: Proxy API
api = Proxy
```

Now we'll need to implement the api, we'll write a basic Haskell functions,
which we would write anyway, we could reuse them in a console application, for example.
```haskell
createCat :: MonadIO m => Connection -> CatName -> m Cat
createCat = error "not implemented"
readCat :: MonadIO m => Connection -> CatName -> m Cat
readCat = error "not implemented"
```

And the problem is that if we try to do
```foo
-- THIS DOESN'T WORK
app :: Application
app = serve api $ createCat :<|> readCat
```
it will fail with a type-error message from GHC. Obviously, GHC cannot conjure
`Connection` for us. We need to pass it in somehow.

Partial application
-------------------

*Partial application* is a simple tool. We can partially apply the
implementation to fit into type required by `serve`. We'll make a situation a
bit more interesting by using a connection pool:
```haskell
app :: Pool Connection -> Application
app pool = serve api $
withResource1 pool createCat :<|> withResource1 pool readCat
where
withResource1 :: MonadBaseControl IO m => Pool a -> (a -> b -> m c) -> b -> m c
withResource1 pool f b = withResource pool $ \a -> f a b
```

As you can see we'd need to wrap every handler in `withResource1`.
It's not very elegant, but **it works**. And is very **simple** to understand.

hoistServer
-----------

`servant` offers the
[`hoistServer`](http://hackage.haskell.org/package/servant-server-0.14/docs/Servant-Server.html#v:hoistServer)
helper function.
which let's you to remove this kind of
boilerplate. We'll rewrite our handlers in MTL-style, with a `MonadDB` type
class. For the sake of example let's also add a `MonadLog` from
[`log-base`](http://hackage.haskell.org/package/log-base) to the first endpoint.
```haskell
class MonadDB m where
withConnection :: (Connection -> m a) -> m a
createCat' :: (MonadDB m, MonadLog m) => CatName -> m Cat
createCat' = error "not implemented"
readCat' :: (MonadDB m) => CatName -> m Cat
readCat' = error "not implemented"
```

Looks good, but how we'll pass a connection (and a logger)? The answer is
obvious, when you know it: we'll need to use a concrete monad implementation, for example:

``` haskell
newtype H a = H { runH :: ReaderT (Pool Connection) (LogT Handler) a }
deriving (Functor, Applicative, Monad, MonadTime, MonadLog)
instance MonadDB H where
withConnection f = H $ do
pool <- ask
withResource pool $ \conn -> runH (f conn)
```

And now `hoistServer` will do the magic:
```haskell
app' :: Pool Connection -> Logger -> Application
app' pool logger = serve api $ hoistServer api nt $ createCat' :<|> readCat'
where
nt :: H x -> Handler x
nt m -> runLogT "api" logger (runReaderT (runH m) pool)
```

The `nt` (for natural transformation) tells how to transform the concrete monad
`H` into servant's `Handler`. The `hoistServer` machinery walks through `ServerT H`
value and applies that transformation, resulting into `ServerT Handler` value.
If `api` has `HasServer` instance, you can `hoistServer` it.

The `hoistServer` is most useful when you have polymorphic handlers defined with
mtl-like monad type-classes, so you can instantiate them all with the same concrete
monad at then end. Note: that if we had concrete `LogT Handler` in some
handler, and `ReaderT (Pool Connection) Handler` in some other one, `hoistServer`
won't help!

So to conclude:

- start with *partial application* to pass arguments into handlers
- later you may transfer to use fancier `hoistServer`.

[Alp Mestanogullari summarised it well](https://github.com/haskell-servant/servant/issues/704#issuecomment-283396827):
*gradually reach for fancier things as your needs grow, never when it's not required*.
@@ -0,0 +1,124 @@
---
title: servant 0.14 released
author: The servant team
toc: true
---

# Introduction

We're happy to announce the release of `servant-0.14`.
This is relatively small release, still containing some new features and
breaking changes.

## Significant changes

- `Stream` takes a status code argument

```diff
-Stream method framing ctype a
+Stream method status framing ctype a
```

([#966](https://github.com/haskell-servant/servant/pull/966)
[#972](https://github.com/haskell-servant/servant/pull/972))

- `ToStreamGenerator` definition changed, so it's possible to write an instance
for conduits.

```diff
-class ToStreamGenerator f a where
- toStreamGenerator :: f a -> StreamGenerator a
+class ToStreamGenerator a b | a -> b where
+ toStreamGenerator :: a -> StreamGenerator b
```

([#959](https://github.com/haskell-servant/servant/pull/959))

- Added `NoFraming` streaming strategy
([#959](https://github.com/haskell-servant/servant/pull/959))

- *servant-client-core* Free `Client` implementation.
Useful for testing `HasClient` instances.
([#920](https://github.com/haskell-servant/servant/pull/920))

- *servant-client-core* Add `hoistClient` to `HasClient`.
Just like `hoistServer` allows us to change the monad in which request handlers
of a web application live in, we also have `hoistClient` for changing the monad
in which *client functions* live.
Read [tutorial section for more information](https://haskell-servant.readthedocs.io/en/release-0.14/tutorial/Client.html#changing-the-monad-the-client-functions-live-in).
([#936](https://github.com/haskell-servant/servant/pull/936))

iF you have own combinators, you'll need to define a new method of
`HasClient` class, for example:

```haskell
type Client m (MyCombinator :> api) = MyValue :> Client m api
hoistClientMonad pm _ nt cl = hoistClientMonad pm (Proxy :: Proxy api) nt . cl
```

- *servant* Add `safeLink' :: (Link -> a) -> ... -> MkLink endpoint a`,
which allows to create helpers returning something else than `Link`.
([#968](https://github.com/haskell-servant/servant/pull/968))

- *servant-server* File serving in polymorphic monad.
i.e. Generalised types of `serveDirectoryFileServer` etc functions in
`Servant.Utils.StaticFiles`
([#953](https://github.com/haskell-servant/servant/pull/953))

- *servant-server* `ReqBody` content type check is recoverable.
This allows writing APIs like:

```haskell
ReqBody '[JSON] Int :> Post '[PlainText] Int
:<|> ReqBody '[PlainText] Int :> Post '[PlainText] Int
```

which is useful when handlers are subtly different,
for example may do less work.
([#937](https://github.com/haskell-servant/servant/pull/937))

- *servant-client* Add more constructors to `RequestBody`, including
`RequestBodyStream`.
*Note:* we are looking for http-library agnostic API,
so the might change again soon.
Tell us which constructors are useful for you!
([#913](https://github.com/haskell-servant/servant/pull/913))

## Other changes

- `GetHeaders` instances implemented without `OverlappingInstances`
([#971](https://github.com/haskell-servant/servant/pull/971))

- Added tests or enabled tests
([#975](https://github.com/haskell-servant/servant/pull/975))

- Add [pagination cookbook recipe](https://haskell-servant.readthedocs.io/en/release-0.14/cookbook/pagination/Pagination.html)
([#946](https://github.com/haskell-servant/servant/pull/946))

- Add [`servant-flatten` "spice" to the structuring api recipe](https://haskell-servant.readthedocs.io/en/release-0.14/cookbook/structuring-apis/StructuringApis.html)
([#929](https://github.com/haskell-servant/servant/pull/929))

- Dependency updates
([#900](https://github.com/haskell-servant/servant/pull/900)
[#919](https://github.com/haskell-servant/servant/pull/919)
[#924](https://github.com/haskell-servant/servant/pull/924)
[#943](https://github.com/haskell-servant/servant/pull/943)
[#964](https://github.com/haskell-servant/servant/pull/964)
[#967](https://github.com/haskell-servant/servant/pull/967)
[#976](https://github.com/haskell-servant/servant/pull/976))

- Documentation updates
[#963](https://github.com/haskell-servant/servant/pull/963)
[#960](https://github.com/haskell-servant/servant/pull/960)
[#908](https://github.com/haskell-servant/servant/pull/908)
[#958](https://github.com/haskell-servant/servant/pull/958)
[#948](https://github.com/haskell-servant/servant/pull/948)
[#928](https://github.com/haskell-servant/servant/pull/928)
[#921](https://github.com/haskell-servant/servant/pull/921))

- Development process improvements
([#680](https://github.com/haskell-servant/servant/pull/680)
[#917](https://github.com/haskell-servant/servant/pull/917)
[#923](https://github.com/haskell-servant/servant/pull/923)
[#961](https://github.com/haskell-servant/servant/pull/961)
[#973](https://github.com/haskell-servant/servant/pull/973))
@@ -36,13 +36,6 @@ main = hakyllWith config $ do
>>= loadAndApplyTemplate "templates/default.html" defaultContext
>>= relativizeUrls

match "tutorial/**" $ do
route (setExtension "html")
compile $ myPandocCompiler
>>= loadAndApplyTemplate "templates/page.html" defaultContext
>>= loadAndApplyTemplate "templates/default.html" defaultContext
>>= relativizeUrls

match "posts/*" $ do
route $ setExtension "html"
compile $ myPandocCompiler
@@ -16,10 +16,10 @@
<div id="navigation">
<a href="/">Home</a>
<a href="/blog.html">Blog</a>
<a href="/tutorial">Tutorial</a>
<a href="/tips.html">Tips and tricks</a>
<a href="https://haskell-servant.readthedocs.io/en/stable/tutorial/index.html">Tutorial</a>
<a href="https://haskell-servant.readthedocs.io/en/stable/cookbook/index.html">Cookbook</a>
<a href="/talks.html">Talks</a>
<a href="https://github.com/haskell-servant/servant">Github</a>
<a href="https://github.com/haskell-servant/servant">GitHub</a>
</div>
</div>