皆さん、こんにちは
最近のJavaScriptのフロントサイドのフレームワークもしくはアーキテクチャは、AngularとReactJSが主流となっているように感じますが、一方で、vue.jsやriot.jsのような大企業がバックにないようなフレームワークにも光が当たってきています。
個人的にはどれがいいというよりは、作成するアプリの性質に応じて使い分けるのがいいんじゃないかなぁと思いますが、弊社内ではAngular, ReactJS, vue.jsを推す人はいるのですが、riot.jsを推す人がいなかったので、じゃあ私がやっちゃおうということでやりました。
TODOアプリとかはすでに公式サイトにあるので、ここではAPIをテストするためのツール作成を通して、riot.jsの挙動を調べてみましょう。
ちなみに今回のはriot 3.0を使っているのでそれ以前のバージョンを使っている場合は、動かない部分があります。
まだ日本語訳されていないので、ちょいと面倒かも。。。
概観
仕様
今回作成したのは、特定のURLにリクエストを投げ、レスポンスをテキストフィールドに書き出すというものです。
UIは以下のとおりです。
riot
riotは「軽量」「シンプル」「コンポーネント」をテーマに作られたフレームワークです。
http://riotjs.com/
http://riotjs.com/v2/ja/
カスタムタグという、オリジナルのタグを作る仕組みを通して、UIとそれに伴う処理をまとめておくことができます。
私のようにモノグサな人間にも、割と簡単に書くことができます。
検証内容
riotの以下の機能について検証しています
- タグの作成
- 入れ子のタグ
- 描画タイミング
実装
大本のHTML
riotを動かすにもまずはエントリーポイントとなるHTMLを作らなければなりません。
HTMLは以下のとおりです。
<html>
<head>
<title>API TEST</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h1>API TEST</h1>
<!-- Main Content tag -->
<test-api></test-api>
<script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
<!-- include the tag -->
<script type="riot/tag" src="tags/test-api.tag"></script>
<script type="riot/tag" src="tags/test-uri.tag"></script>
<script type="riot/tag" src="tags/test-input.tag"></script>
<!-- include riot.js -->
<script src="https://cdn.jsdelivr.net/riot/3.0/riot+compiler.min.js"></script>
<!-- mount the tag -->
<script>riot.mount('*')</script>
</div>
</body>
</html>
bootstrapは見た目をちょっと良くするために導入し、jqueryはajaxを容易に使いたいので入れています。
このHTMLのなかでメインとなるのはtest-api
タグで、この中にほぼすべての処理が入っています。
riotで使用できるオリジナルタグの定義はtags
ディレクトリに入れてあります。
最後のriot.mount('*')
で読み込んだタグを全てマウントしています。
子タグの作成
メインのタグであるtest-api
はサイズが大きいので、先にサイズの小さいtest-uri
, test-input
を先に実装してみましょう。
<test-uri>
<div class="form-inline">
<div class="form-group">
<label for="uri">URI: </label>
<input class="uri form-control" type="text" style="width: 600px" ref="uri"></input>
</div>
</div>
</test-uri>
tag
という見慣れない拡張子を使っていますが、これがriotで使用されるカスタムタグを定義するためのファイルになります。
カスタムタグはそのタグ名で囲った範囲を新たなタグの定義として認識します。
ここでは何か特別な処理があるわけではないので、見た目は通常のHTMLとほとんど同じです。
唯一ref
という属性が定義されていますが、これは後で使います。
同様にtest-input
タグも定義しましょう。
<test-input>
field: <input type="text" ref="field"></input>
value: <input type="text" ref="value"></input>
</test-input>
丸裸のinput
二つだけの構成となりました。
わざわざカスタムタグを定義する必要もなさそうですが、なんとなく外に出しています。
メインのタグを定義する
UIの定義
今回のAPIテストツールのメインとなるタグを作成しましょう。
まず、UIの部分だけ作ってみます。
<test-api>
<!-- tags/test-uri.tag で作ったタグ -->
<test-uri></test-uri>
<br>
<div class="form-group">
<label for="method">method: </label>
<select ref="method">
<option each={ method in methods } value={ method }>
{ method }
</option>
</select>
</div>
<div>
<h2>Field and Value</h2>
<button onclick={ addItem } >add</button>
<ul>
<li each={ value, key in reqItems }>
<!-- tags/test-input.tag で作ったタグ -->
<test-input></test-input>
<button onclick={ deleteItem } >remove</button>
</li>
</ul>
</div>
<button onclick={ showResult } >result</button>
<br>
<textarea class="form-control" rows="20">{ result }</textarea>
<!-- 後略 -->
</test-api>
ここではいくつか特殊な記法が出てきます。
まず、後述するタグのプロパティに対しては中括弧でアクセスできます(this.item
にアクセス => { item }
)。
optionやliタグについているeach
属性は配列の各要素を使って、そのタグを生成します。
例えば、methodのoption
の部分は実際には以下のように展開されています
<option value="GET"> GET </option>
<option value="POST"> POST </option>
<option value="PUT"> PUT </option>
<option value="DELETE"> DELETE </option>
処理の作成
次に、プロパティの定義と処理の部分を作成します。
この部分はカスタムタグの中でscript
タグで定義すれば良いです。
<test-api>
<!-- 中略 -->
<script>
this.methods = ['GET', 'POST', 'PUT', 'DELETE'];
this.reqItems = [];
this.result = '';
// 中略
</script>
</test-api>
まずはリクエストパラメータを追加・削除する処理を作ってみましょう。
UIの部分で、パラメータの追加はaddボタンのonclick
で起動するaddItem
メソッドで、パラメータの削除は各removeボタンのremoveItem
になります。
addItem() {
this.reqItems.push({field: '', value: ''})
}
deleteItem(e) {
let key = e.item.key
this.reqItems = this.reqItems.filter((v, i) => i != key)
}
メソッドの書き方はこんな感じでできます。
addItem
はreqItems
に要素を追加し、deleteItem
は押したボタンが属するli
タグに紐付いたオブジェクトを削除しています。
これだけで動きます。妙に簡単ですね。
通信処理の作成
次に、リクエスト処理の部分を書いてみましょう。
まずはresult
ボタンを押したときに起動するメソッドを作ってみましょう。
showResult() {
let uri = this.tags['test-uri'].refs.uri.value
if (typeof this.tags['test-input'] == 'undefined') return this.query(uri, [])
let inputs = this.tags['test-input']
if (typeof inputs[0] == 'undefined') inputs = [inputs]
this.query(uri, inputs)
}
入れ子のタグ要素は上述したようにthis.tags
に格納されています。
また、各カスタムタグの中でref
属性が付加されたDOMに、this.refs['refname']
でアクセスすることができます。
今回注意すべきはこのrefsによるアクセスはversion 3からの追加であることです。
version 2では使えないこと、およびversion 2でできていたname,idへの要素への直接アクセスができなくなったことに注意しておきましょう。
最後に通信の部分を見てみましょう。
query(uri, inputs) {
const reqParam = {}
inputs.forEach(v => {
let field = v.refs.field.value
let value = v.refs.value.value
reqParam[field] = value
})
$.ajax({
type: this.refs.method.value,
url: uri,crossDomain: true,
data: reqParam
}).done(res => this.renderResult(res))
}
renderResult(data) {
this.result = JSON.stringify(data, null, "\t")
this.update()
}
jQueryのajax使っているのは単純にソッチのほうが慣れているからです。
最後の部分ですが、this.result
に値を入れただけでは表示が更新されないようで、this.update()
メソッドで、明示的にレンダリングさせています。
一方、eachで監視されているプロパティの変更においてはupdateをかけなくても表示が更新される模様です。
サーバサイドの実装
本題と外れますが、サーバサイドはKoaを使っています
npm i -S koa koa-router koa-body
で必要なモジュールをインストールしてから
"use strict";
const koa = require('koa');
const app = koa();
const router = require('koa-router')();
const koaBody = require('koa-body')()
router
.get('/app', function * (){
queryParam(this, this.query)
})
.post('/app', koaBody, function * (next){
queryParam(this, this.request.body)
})
function queryParam(ctx, params) {
let query = params
let url = ctx.url
ctx.response.set("Content-type", "application/json; charset=UTF-8")
let body = {uri: url, param: query}
console.log(body)
ctx.body = JSON.stringify(body)
}
app.use(router.routes())
app.use(require('koa-static-server')({rootDir: '', rootPath: '/client'}));
app.listen(8888);
こんな感じで、非常に単純に実装しちゃってます。
まとめ
HTML書くのは慣れているんですが、JavaScriptでDOMを制御しようとすると、非常に面倒なんですよね。
そんなわけで、フロントのUIを簡単に制御できるJSのフレームワークのなかで、riotを使ってAPIテストツールを作ってみました。
はじめは動きがわからない部分もありましたが、半日程度で動きは把握できました。
謳い文句にあるだけあって、学習コストは非常に小さいと思います(とはいえ、HTMLとJSの知識前提ですが)。
今回はこんなところです。