Pharo + Seaside で簡単 RESTful サービス
とあるプログラムのテスト用に、単純な JSON を返却する RESTful サービスを簡単にサクッと作れないかなと思う中、「Pharo Smalltalk」と「Seaside」を使ってみたらとても簡単だったのでご紹介します。
Pharo Smalltalk の準備
基本的にはダウンロードページより各環境用のアーカイブをダウンロードし、任意の場所へ解凍するだけなのですが、Zeroconf Script を用いて構築することもできます。
Windows
アーカイブを解凍した先にある「Pharo.exe」に「Pharo.image」をドラッグアンドドロップします。
Mac OSX
アーカイブを解凍して生成される「Pharo〜.app」をダブルクリックして起動します。
Zeroconf Script
$ cd $ mkdir rest && cd $_ $ curl get.pharo.org/stable+vm | bash
起動は
$ ./pharo-ui Pharo.image
とします。
起動するとこのようなウィンドウが開きます。
Seaside の導入
World (Desktop) をクリックすると World メニューが開きます。
Configuration Browser を開きたいのでメニューから「Tools > Configuration Browser」を選択します。
Seaside3 を選択して Install Stable Version をクリックします。
しばらく待つとインストールが完了しアイコンが変化します。
Seaside の REST 機能はアドオンとして提供されています。スクリプトを評価して導入を行うので Playground を開きます。
Playground が開いたらここに Smalltalk コードを入力します。
Gofer new smalltalkhubUser: #Seaside project: #Seaside30Addons; package: 'Seaside-REST-Core'; package: 'Seaside-Pharo-REST-Core'; package: 'Seaside-Tests-REST-Core'; load.
実行ボタンをクリックします。
スクリプトを評価した結果の GoferLoad オブジェクトが返されたら導入完了です。
Web Application Server の起動
Seaside の導入により、World メニューに Seaside Control Panel が追加されます。「Tools > Seaside Control Panel」を選択します。
開いた Seaside Control Panel 上で右クリックするとメニューが開きます。ここから「Add adaptor...」を選択します。
追加するアダプタ「ZnZincServerAdaptor」を選択します。
任意のポート番号を設定します。
一覧に追加されたサーバアダプタを選択し、「Start」をクリックします。
ヒトデのアイコンが明るく変化したらサーバ起動完了です。
イメージの保存(余談)
ここまで「Seasideの導入」「REST アドオンの導入」「アプリケーションサーバの起動」としてきましたが、この状態でイメージを保存しておくと必要な時にすぐ RESTful サービスを作成できるので便利です。(多くの Smalltalk 実装がそうであるように Pharo Smalltalk も仮想マシン上でイメージを展開することで環境が提供されます。VMware や VirtualBox などによる仮想化環境をイメージしてもらえれば理解し易いかと思います。)
World メニューから「Save as...」を選択し「名前をつけて保存」しておきます。
ファイル選択ダイアログが開くので任意のファイル名を指定して保存します。
次回からは、ここで保存したイメージファイルを開けばアプリケーションサーバが起動した状態から始められます。便利ですね。(^_^)
RESTful ハンドラクラスの作成
閑話休題、ここから HTTP リクエストで JSON を返すハンドラを作成するコーディングになります。コーディングには「System Browser」というものを使うので World メニューから選択します。
System Browser 下部のコードペインにクラス定義のテンプレートが表示されています。
Object subclass: #NameOfSubclass instanceVariableNames: '' classVariableNames: '' category: ''
「WARestfulHandler」クラスを継承した「MyHandler」クラスを「Rest-Service」カテゴリに作成します。
WARestfulHandler subclass: #MyHandler instanceVariableNames: '' classVariableNames: '' category: 'Rest-Service'
コードを編集したら「Accept」します。Windows では 「Ctrl + s」、Mac OSX では「Cmd + s」で Accept できます。
MyHandler クラスを Web アプリケーションとして登録するための初期化メソッドを「クラスメソッド」として定義します。クラスメソッドを作成するには「Class side」をチェックします。
MyHandler が表示されているクラスペインの右にあるメソッドカテゴリペインの「no messages」を選択するとコードペインにクラスメソッドのテンプレートが表示されます。
このテンプレートを次のように変更します。
initialize WAAdmin register: self at: 'credentials'
このコードは MyHandler クラスを「credentials」という名前のウェブアプリケーションとして登録することを意味します。
こちらも先ほどと同様に Accept すると名前の入力を促されます。環境の Author を指定するだけなので適当に入力して OK ボタンをクリックします。
クラスメソッド「initialize」が定義されました。メソッドカテゴリペインの「-- all --」を選択すると initialize メソッドが作成されたことが分かります。
この initialize メソッドを評価する簡単な方法は、メソッドの左に表示されているスクリプトアイコンをクリックすることです。
「クラスを(再)初期化してもよい?」と聞かれるので Yes ボタンをクリックします。
これで「http://localhost:9090/credentials」が登録されました!
RESTful ハンドラメソッドの作成
後は JSON を返すインスタンスメソッドを定義するだけです。
クラスメソッドを定義する際にチェックした「Class side」のチェックを外し、クラスメソッドの時と同様にメソッドをコーディングします。
メソッドの内容は次のようになります。
credentials <get> <produces: 'application/json'> ^ '{ "Code": "", "LastUpdated": "", "Type": "", "AccessKeyId": "", "SecretAccessKey": "", "Token": "", "Expiration": "" }'.
- 1行目
- メソッド名
- 2行目
- HTTP メソッドの GET に反応しますよという get プラグマ
- 3行目
- レスポンスとして JSON を返却しますよという produces: プラグマ
- 5行目以降
- 返却される JSON 文字列(^ は return を表します。)
Accept して「http://localhost:9090/credentials」へアクセスすると
JSON が表示されました!ブラウザの DevTools などでコンテンツタイプが「application/json」であることも確認できるはずです。
更にメソッドを以下のように変えて Accept すれば
credentials <get> <produces: 'application/json'> | now | now := DateAndTime now. ^ '\{ "Code": "", "LastUpdated": "{1}", "Type": "", "AccessKeyId": "AKIAIOSFODNN7EXAMPLE", "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", "Token": "", "Expiration": "{2}" \}' format: {now. now + (1 day)}.
このようになります!アプリケーションサーバの再起動などを要せずにすぐ値を変えられるので便利です!
まとめ
今回私はこのような使いかたをしましたが、本来はしっかりとしたウェブアプリケーションを構築できる環境です。この記事で興味を持たれた方はちょっとしたものから便利に使ってみてはいかがでしょうか。