軽量HaskellウェブフレームワークServant

Tech > Haskell

軽量で型安全なウェブフレームワーク Servant

Servantプロジェクト作成

$ stack new projname servant

ビルド

$ stack build

実行

http://localhost:8080/users でJSONの出力が確認できる

$ stack build

ルーティング

URLのルーティングは API型で定義する、 DataKind拡張などを利用して型に変換する /users というURLの定義は以下のように書くMethod は GET で レスポンスは JSON形式の User配列という意味

type API = "users" :> Get '[JSON] [User]
  ...

/userid/[数値] などパラメータを取得したい場合、 Capture を利用する

    :<|> "userid" :> Capture "i" Int :> Get '[JSON] (Maybe User)

/search?username=[文字列] のようなクエリパラメータを利用する場合は QueryParam を利用する

    :<|> "search" :> QueryParam "username" String :> Get '[JSON] [User]

Method の POST の利用方法で入力のリクエストにJSON形式のパラメータ ModInfo 型をしていする場合は以下のとおり

    :<|> "usermod" :> ReqBody '[JSON] ModInfo :> Post '[JSON] [User]

:<|> でURLを複数並べる

type API = "users" :> Get '[JSON] [User]
         :<|> "userage" :> Capture "p" Int :> Get '[JSON] [User]
         :<|> "userid" :> Capture "i" Int :> Get '[JSON] (Maybe User)
         :<|> "search" :> QueryParam "username" String :> Get '[JSON] [User]
         :<|> "usermod" :> ReqBody '[JSON] ModInfo :> Post '[JSON] [User]

パラメータ

パラメータやレスポンスの値をJSON化したい場合は、Jsonクラスのインスタンスとするために $(deriveJSON defaultOptions ’’ModInfo) を書く

...
data ModInfo = ModInfo
  { modId :: Int
  , modAge :: Int
  , modFirstName :: String
  , modLastName  :: String
  } deriving (Eq, Show)

$(deriveJSON defaultOptions ''ModInfo)
...

こうすることで、Haskellが型をJSON化してくれる

Handler

別の世界ではコントローラーと呼ぶレイヤーだと思ってる、しらんけど、Handlerの型情報

newtype Handler a = ExceptT ServerError IO a -> Handler a

で定義されている、ExceptTは

newtype ExceptT e m a = ExceptT (m (Either e a))

ServantのHandlerはIOモナド内で結果aかエラーのeを返すすごくシンプルな関数定義となっている、そして ServerError は

   type ServerError :: *
   data ServerError
     = ServerError { errHTTPCode :: Int
                   , errReasonPhrase :: String
                   , errBody :: Data.ByteString.Lazy.Internal.ByteString
                   , errHeaders :: [Network.HTTP.Types.Header.Header]
                   }
     	-- Defined in ‘Servant.Server.Internal.ServerError’
   instance Eq ServerError
     -- Defined in ‘Servant.Server.Internal.ServerError’
   instance Show ServerError
     -- Defined in ‘Servant.Server.Internal.ServerError’
   instance Read ServerError
     -- Defined in ‘Servant.Server.Internal.ServerError’

エラーコードなどが定義されている

コード

JSON形式しか返却できませんが、サンプルはgithubです、利用方法は README.md を参照してください

https://github.com/calimakvo/svty

やはり厳格な型システムのおかげで軽量でも安全に作れるところが素晴らしいと思います

参考資料

たしか、Haskell Day 2018の勉強会のこのお話がきっかけでServant知りました、良い資料ですご一読ください

Haskell × Servantで作る、安全かつ高速なAPI開発

Posted on 2023-02-12 16:21:37

はじめまして

お茶の国静岡で、焼酎のお茶割なんか罰当たりで飲んだことはありません、常に一番搾りを嗜む静岡極東のBBQerです、最近まわりのエンジニアの方々がお料理を上手にやっている姿を恨めしそうに横目に見ながら、軟骨ピリ辛チクワを食べています、みなさんよろしく。

Posted

Amazon

tags

家系 日本酒池 広井酒店 やがら やっぱた 刺身 丸干し 鯵 東京マラソン fpm php82 servant thread spawn Rust Oracle Linux 8 microcode firmware linux openzfs zfs gitea 麒麟 真野鶴 金鶴 日本酒 docker oracle pod podman cli virtualbox VirtualBox epub mobi calibre mask lens ワンライナー php 海 redmine Linux Oracle Map OMap omap map 夏 BBQ カテゴリ管理 カテゴリ timestamp date oracle database string 麦焼酎 ダービー process 磨き蒸留 広井酒店、日本酒 芋焼酎 酒 焼酎 ゆるキャン 広井酒店、日本酒池 spring framework java persistent spring session session spring hdbc-odbc persistent-odbc odbc day utctime スィート レマンの森 elm初期化 elm バイク xlr80 esqueleto database xl2tpd strongswan vpn l2tp ipsec 正月 ゲーム grub nginx systemctl portage 豚骨 圧力鍋 yesod-auth-hashdb yesod-auth