3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Yesodにserversession-backend-redisを組み込んで動かしてみたのでメモしておく

Posted at

学習がてら、HaskellのWebフレームワークであるYesodと、セッション管理をサポートするライブラリであるserversessionを組み合わせて動かしてみました。

今回は、stackのtemplateであるyesodweb/simpleを利用して、redissessionというプロジェクト名にしました。

stack new redissession yesodweb/simple

今回は、SessionストレージにRedisを使いたかったので、serversessionというライブラリを使いました。
(このライブラリは長いことメンテナンスされていないようですが、今回はHaskellでのセッション周りの実装例を見てみることが目的なので、気にせず進みます。)

まずは、package.yamlにserversessionパッケージの情報を追記します。
フロントエンドとしてYesod、バックエンドとしてRedisを使用するので、serversession-frontend-yesodとserversession-backend-redisも追記します。
また、serversesion-backend-redisはhedisというパッケージに依存しているので、それも追記します。

package.yaml
dependencies:
(中略)
- serversession == 1.0.1
- serversession-frontend-yesod == 1.0
- serversession-backend-redis == 1.0.3
- hedis < 0.11

serversession-frontend-yesodとserversession-backend-redisは、今回使用したStackageのresolverのlts-16.20に含まれていなかったため、stack.yamlにも追記します。
また、このままではパッケージ間のバージョン依存関係の不整合によりエラーが発生してしまったので、"allow-newer: true"を設定して、バージョン依存関係の不整合を無視します。
今回はまず動かしてみることが目的なので、これでよしとします。

stack.yaml
extra-deps:
- serversession-frontend-yesod-1.0
- serversession-backend-redis-1.0.3

allow-newer: true
src/Foundation.hs
import ...()

-- 以下を追記
import Web.ServerSession.Backend.Redis (RedisStorage(..))
import Web.ServerSession.Frontend.Yesod (simpleBackend, setCookieName, setSecureCookies)
import qualified Database.Redis as Redis

(中略)

data App = App 
    { appSettings    :: AppSettings
    , appStatic      :: Static -- ^ Settings for static file serving.
    , appHttpManager :: Manager
    , appLogger      :: Logger
    , appConn        :: Redis.Connection --追加
    }
src/Foundation.hs
instance Yesod App where

(中略)

  makeSessionBackend :: App -> IO (Maybe SessionBackend)
  makeSessionBackend = simpleBackend opts . createStorage
    where createStorage appl = RedisStorage (appConn appl) idleTimeoutSec absoluteTimeoutSec
          idleTimeoutSec     = Just $ 60*10
          absoluteTimeoutSec = Just $ 60*30
          opts               = setCookieName "REDISSESSION_ID"
                             . setSecureCookies False
src/Application.hs
import qualified Database.Redis as Redis

makeFoundation :: AppSettings -> IO App 
makeFoundation appSettings = do
    -- Some basic initializations: HTTP connection manager, logger, and static
    -- subsite.
    appHttpManager <- getGlobalManager
    appLogger <- newStdoutLoggerSet defaultBufSize >>= makeYesodLogger
    appStatic <-
        (if appMutableStatic appSettings then staticDevel else static)
        (appStaticDir appSettings)
    appConn <- Redis.connect Redis.defaultConnectInfo  -- ここを追記                                                                                                                                                                                       

    -- Return the foundation
    return App {..}
src/Handler/Home.hs
 {-# LANGUAGE NoImplicitPrelude #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE TemplateHaskell #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE QuasiQuotes #-} --追加

import Web.ServerSession.Frontend.Yesod (forceInvalidate, ForceInvalidate(..))
import Import
import Yesod.Form.Bootstrap3 (BootstrapFormLayout (..), renderBootstrap3)
import Text.Julius (RawJS (..))

import Web.ServerSession.Frontend.Yesod (forceInvalidate, ForceInvalidate(..)) 
src/Handler/Home.hs
getHomeR :: Handler Html
getHomeR = do
    sess <- getSession
    forceInvalidate CurrentSessionId -- これを呼ぶとセッションIDが再採番される
    defaultLayout
        [whamlet|
            <form method=post>
                <input type=text name=key>
                <input type=text name=val>
                <input type=submit>
            <h1>#{show sess}
        |]  

postHomeR :: Handler ()
postHomeR = do
    (key, mval) <- runInputPost $ (,) <$> ireq textField "key" <*> iopt textField "val"
    case mval of
        Nothing -> deleteSession key 
        Just val -> setSession key val 
    liftIO $ print (key, mval)
    redirect HomeR

動かしてみます。

Redisを立ち上げておきます。

$ redis-server

Webサーバを起動します

$ stack exec -- yesod devel

Webサーバが立ち上がったので、Webブラウザで、localhost:3000にアクセスします。

スクリーンショット 2021-01-06 23.37.17.png

Set-Cookieヘッダーに、「REDISSESSION_ID」フィールドがあります。うまく動いていそうです。
次に、Sessionストレージにデータを保存してみます。
Keyは「hoge」、Valueは「fuga」を指定します。

スクリーンショット 2021-01-06 23.37.33.png

Session情報が画面に表示されました。ちゃんと動いていそうです。
(「forceInvalidate CurrentSessionId」を呼んだので、SetCookieヘッダーの「REDISSESSION_ID」の値が変わっていますが、このタイミングでは本来必要ありません。)

スクリーンショット 2021-01-06 23.38.03.png

redis-cliでも、Redisに格納されているデータを確認しておきます。

スクリーンショット 2021-01-06 22.52.08.png

ブラウザで入力したデータが、ちゃんと保存されています。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?