Haskell Servant 入門 (HTTPS対応)

# Https in Haskell with Servant

Servant を TLS(HTTPS) に対応させる方法を紹介します。
本記事のソースコードは以下のリポジトリにおいてあります。
http://github.com/algas/haskell-servant-cookbook
クライアントとサーバをそれぞれ HTTPS で扱えるようにします。
(サーバ側はリバースプロキシで対応することの方が多いと思いますが)

## Client

http-client-tls を使います。
`tlsManagerSettings` を `defaultManagerSettings` の代わりに用います。

```hs:https-client/Main.hs
{-# LANGUAGE DataKinds         #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where

import           Control.Monad.Trans.Except (ExceptT, runExceptT)
import           Data.Proxy
import           Data.Text                  (Text)
import qualified Data.Text                  as T
import           HelloApi
import           Network.HTTP.Client        (Manager, newManager)
import           Network.HTTP.Client.TLS    (tlsManagerSettings)
import           Servant.API
import           Servant.Client

type SimpleAPI  = Get '[PlainText] Text

simpleApi :: Proxy SimpleAPI
simpleApi = Proxy

simple = client simpleApi

queries :: Manager -> BaseUrl -> ExceptT ServantError IO (Text)
queries manager baseurl = do
    h <- simple manager baseurl
    return h

main :: IO ()
main = do
    manager <- newManager tlsManagerSettings
    let baseUrl = BaseUrl Https "localhost" 8080 ""
    res <- runExceptT $ queries manager baseUrl
    case res of
        Left err -> putStrLn $ "Error: " ++ show err
        Right p -> do
            print p
```

## Server

warp-tls を使います。
`runTLS`, `tlsSettings` を用います。

```hs:https-server/Main.hs
{-# LANGUAGE DataKinds         #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where

import           Data.Text                   (Text)
import           Network.Wai
import           Network.Wai.Handler.Warp
import           Network.Wai.Handler.WarpTLS
import           Servant
import           Servant.API

type SimpleAPI  = Get '[PlainText] Text

simpleApi :: Proxy SimpleAPI
simpleApi = Proxy

server :: Server SimpleAPI
server = return "Simple"

app :: Application
app = serve simpleApi server
main :: IO ()
main = do
    runTLS (tlsSettings "server.crt" "server.key") (setPort 8080 defaultSettings) app
```

## Dependencies

```hs:haskell-servant-cookbook.cabal
executable https-client
  hs-source-dirs:      https-client
  main-is:             Main.hs
  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
  build-depends:       base
                     , text
                     , aeson
                     , http-client
                     , http-client-tls
                     , transformers
                     , servant
                     , servant-client
                     , haskell-servant-cookbook
  default-language:    Haskell2010

executable https-server
  hs-source-dirs:      https-server
  main-is:             Main.hs
  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
  build-depends:       base
                     , text
                     , aeson
                     , wai
                     , warp
                     , warp-tls
                     , servant
                     , servant-server
                     , haskell-servant-cookbook
  default-language:    Haskell2010
```

## 参考文献
https://hackage.haskell.org/package/scotty-tls
http://d.hatena.ne.jp/ozuma/20130511/1368284304