WebサーバーとDBとの連携(1)Clojureでのサーバーの立ち上げ

人工知能技術 セマンティックウェブ技術 オントロジー技術 検索技術    データベース技術  デジタルトランスフォーメーション技術  Visualization & UX   ワークフロー&サービスプログラミング Clojure

前回述べた機械学習の結果を利用するにはデータベースもしくは検索エンジンにデータを投入して活用するのが最も手早くできる方法となる。クライアントのUIは、nodeやreactあるいはD3.js等を利用して見える化し、サーバー側でデータベースあるいは検索エンジンとREST等を介してつなげる構成だ。

今回はサーバー側のシステム構築について述べてみたい。NodeとEXPRESSを用いて構築する方法もあるが、少し複雑なビジネスロジックの構築を念頭に、Clojureを使ったものを紹介する。

Clojureでサーバー(ウェブ)アプリケーションを構築する手段も多々あるが、比較的ポピュラーなものとして”Ring“と”compojure“そして”clj-http“を利用してみる。

まずRingについて、RingはWeb サーバーと Web アプリケーションやフレームワーク間の標準的なインターフェイスを定めたもので、Ruby でいう Rack 、 Python でいう WSGI にあたるものとなる。Ringには4つのコンポーネント(ハンドラー、ミドルウェア、リクエストマップ、レスポンスマップ)があり、役割としてはハンドラーがクライアントからのリクエストマップを受け取り、レスポンスマップを返し、ミドルウェアはシンプルなハンドラーの機能を補うものとなる。一番シンプルなハンドラー以下のようになる。

(defn handler [req]
  {:status 200
   :headers {"Content-Type" "text/plain"}
   :body (:remote-addr req)})

Handlerという関数が定義されて(defn)、reqという引数(入力)を受けて、送信するレスポンスデータが定義されている。

そもそも、インターネットでの通信はTCP(Transmission Control Protocol)やIP(Internet Protocol)で規定された手順で通信パケットの送受信を行い。そのプロトコルの上でウェブブラウザ(クライアント)とサーバーがHTTP(Hypertext Transfer Protocol)あるいはHTTPS(Hypertext Transfer Protocol Secure)を使って通信する形となる。TCP/IPがデータの塊を誤りなく送信する手段であるのに対して、HTTPはクライアントがサーバにリクエストメッセージとして「何を」「どうして」欲しいのかを伝え、サーバはこれにレスポンスメッセージを返すものとなる。この時、URLが「何を」、メソッドが「どうして」に当たる。

Ringのリクエストマップ、レスポンスマップは上記のコード例のように、これらをClojureのデータ構造であるedn((extensible data notation)で表すものとなる。

実際にRingのリクエストマップに現れるキーは以下のようなものとなり、

:server-port リクエストをハンドルしたポート番号
:server-name 解決されたサーバー名もしくは IP アドレス
:remote-addr クライアントか最後にリクエストを投げたプロキシの IP アドレス
:uri リクエスト URI (ドメイン名以下のフルパス)
:query-string もしあればクエリ文字列
:scheme トランスポートプロトコル :http または :https
:request-method HTTP リクエストメソッド :get, :head, :options, :put, :post, :delete のいずれか
:headers ヘッダーの文字列を小文字化したキーを持つマップ
:body もしあればリクエストボディのための InputStream

ハンドラーが作成するレスポンスマップは以下の 3 つのキーを持つ

:status HTTP ステータス
:headers クライアントへと返す HTTP ヘッダー
:body レスポンスボディ

レスポンスマップのキーであるステータスは HTTP RFC で定義されているものと同じで、 200 や 404等のウェブブラウザ上でよく見かけるものとなる。

当初の目的であるデータベースとの連携のケースでは、リクエストマップでデータベース側の設定を反映したものに、リスポンスマップでAPIに規定された情報に合わせた構成にするイメージとなる。

ここで具体的なサーバーの立ち上げを行う。まずproject.cljファイルにringのライブラリを追加する。

:dependencies [[org.clojure/clojure "1.10.1"]
                           [ring "1.8.2"]]

次にsrcのcore.cljを以下のようにする。

(ns my-app.core
  (:require [ring.adapter.jetty :as server]))

(defonce server (atom nil))  ;;  (1)

(defn handler [req]                  ;;(2)
  {:status 200
   :headers {"Content-Type" "text/plain"}
   :body "Hello, world"})

(defn start-server []                 ;;(3)
  (when-not @server
    (reset! server (server/run-jetty handler {:port 3000 :join? false}))))

(defn stop-server []               ::(4)
  (when @server
    (.stop @server)
    (reset! server nil)))

(defn restart-server []           ;;(5)
  (when @server
    (stop-server)
    (start-server)))

(1)はサーバーのインスタンスの生成。(2)でハンドラー関数を設定して、(3)でサーバーをスタート、(4)でサーバー停止と(5)はリスタートになる。上記のファイルをspacemacs上で開き、「SPC」「m」「s」「i」を順に押してreplサーバーを起動し、それぞれの関数の後ろで「CTRL」「c」「e」を同時に押すと評価ができる。start-serverまで評価が終わった時点でブラウザ上で「http://localhost:3000/」を入力すると”Hello world”が見える。また、ターミナル上で「curl -i localhost:3000/」と入力しても、レスポンスが確認できる。

今回はClojureのringを使ったサーバーの立ち上げまでを述べた。次回はcompojureとclj-httpを使ったルーティングまで述べられればと思う。

コメント

  1. […] 機械学習等の結果をデータベースに入れて活用することを目的として、前回はまずサーバーの立ち上げまで行った。次のステップとしてルーティングを述べたい。 […]

  2. […] 具体的な実装例はwebサーバーとDBの連携にて述べる。 […]

  3. […] WebサーバーとDBの連携(1) Clojureでのサーバーの立ち上げ […]

  4. […] WebサーバーとDBの連携(1) Clojureでのサーバーの立ち上げ […]

  5. […] 「PHPフレームワークLaravel Webアプリケーション開発」より。前回はLaravelを使ったアプリケーションの構築の概略について述べた。今回はLaravelアプリケーションの起動から終了までの流れを追ってみる。今回の記事は以前述べたClojureでのウェブアプリケーションの流れと比較するとより理解が深まると思う。 […]

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