HaskellでHello WorldのWebアプリケーションに再挑戦

前回までのあらすじ: Yesodを使ってHello Worldをしようとして、Hello Worldすら表示できませんでした。
HaskellのWebフレームワークYesodでHello World
Haskellの言語を学んでも、Webアプリケーションの作り方は分からないと気づいたので、この本を読みました。
51hiZNtLryL
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/

スクリーンショット 2019-05-06 14.07.49
開けました!

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アプリケーションを作る、という試みでした!
前回は失敗しましたが、今回はなんとか形になりました。次は、何か簡単なものを作れるか、挑戦してみようと思います。

タイトルとURLをコピーしました