前回までのあらすじ: Yesodを使ってHello Worldをしようとして、Hello Worldすら表示できませんでした。
HaskellのWebフレームワークYesodでHello World
Haskellの言語を学んでも、Webアプリケーションの作り方は分からないと気づいたので、この本を読みました。
Haskellで作るWebアプリケーション 遠回りして学ぶYesod入門
WAIが使えそう
Yesodを使わなくても、最小構成のWebアプリケーションが作れそうでした。それを試してみます。
WAI(Web Application Interface)という仕様と、WarpというWebサーバを使用します。
GitHub – yesodweb/wai: Haskell Web Application Interface
WAIは仕様なので、この仕様を使ってWebサーバを実装したり、Webアプリケーションフレームワークを開発したりできます。しかし、Yesodが開発しているので、実質的にYesodのための仕様と実装、と捉えて良さそうです。
いずれにしても、重厚なYesodというフレームワークを使うより、WAIというシンプルな仕様を使って実装したほうが、Hello Worldの理解が進みそうです。
コマンドラインのHello World
その前に、まずは、コマンドラインのHello Worldを、stackでビルドしてみます。
simpleテンプレートを利用してプロジェクトを作成します。
stack new wai-helloworld simple
以前のブログで、yesod-sqliteを使って作成したときより、かなりシンプルになりました。
$ tree . -L 1
.
├── LICENSE
├── README.md
├── Setup.hs
├── src
├── stack.yaml
└── wai-helloworld.cabal
1 directory, 5 files
試しに、そのままビルドして実行してみます。
stack build
stack exec wai-helloworld
// => hello world
コマンドラインにhello worldと表示されるアプリケーションになりました!
WAIでWebアプリケーションを作る
このシンプルなプロジェクトを、Webアプリケーション化していきます。
まずは、src/Main.hs を書き換えます。
もともと、コマンドラインにhello worldを出力する処理が書かれているので、以下のコードで上書きします。
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Network.HTTP.Types (ok200)
import Network.Wai (Application, responseLBS)
import Network.Wai.Handler.Warp (run)
app :: Application
app _ respond =
respond $ responseLBS
ok200
[("ContentType", "text/plain")]
"Hello World!
"
main :: IO ()
main = run 8080 app
詳しい説明は後ほど!
http-types, wai, warpという依存を使用しているので、wai-helloworld.cabalのbuild-dependsに追加します。
build-depends:
base >= 4.7 && < 5
, http-types
, wai
, warp
ブラウザからアクセスしてみる
ビルドして起動してみます。
stack build
stack exec wai-helloworld
これでWebサーバが待機状態になるので、早速ブラウザからアクセスしてみます。
open http://localhost:8080/
WarpのWebサーバの起動
コードについて少し解説していきます。
main関数は、Warpモジュールのrun関数のみです。
main :: IO ()
main = run 8080 app
このrun関数は、ポート番号と、Application関数を受け取って、IOアクションを返す関数になっています。
run :: Port -> Application -> IO ()
ポート番号は説明するまでもないとして、Applicationはこのように型定義されています。
type Application = Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived
Requestと、ResponseをIO ResponseReceivedに変換する関数を受け取って、IO ResponseReceivedを返します。
RequestをResponseにする関数
ということは、Requestを受け取ってResponseを返す関数が作れれば、よさそうです。
そこだけ切り出すなら、こういう感じになります。
requestToResponse :: Request -> Response
requestToResponse _ =
responseLBS
ok200
[("ContentType", "text/plain")]
"Hello World!
"
リクエストを受け取ってレスポンスを返す、って、Webアプリケーションの仕様そのものです。
当たり前のことを偉そうに書いてます・・。
終わりに
以上、HaskellでHello WorldのWebアプリケーションを作る、という試みでした!
前回は失敗しましたが、今回はなんとか形になりました。次は、何か簡単なものを作れるか、挑戦してみようと思います。