17/02/07雑記
ちょっと本格的にAngularを再開。
色々作りこんでいく中でいくつか悩みとアイディアが出たのでメモ。
RestAPIにするか否か
顧客管理のようなシステムを作っている。
顧客への「発送」業務があり、これは顧客によりあったりなかったりする。
データモデルがつまり 顧客
1 ― * 発送
という形になっている。
基本的にresource型のRestfulAPIを守ろうとしたが、 どうしてもブラウザ上で「顧客」を登録してから「発送」を登録することになる。
ただでさえ遠いWebサーバーに2往復もするのに加えて、 業務手続でできれば分離したいコードが、準コントローラーなコード中にむき出しになってしまう。 しかもこれは、1画面に1つ占有するコードみたいなもので、再利用が難しい。(思い切ってService化するのもアリだが)
Restじゃなくて、普通にWebAPI化しようとも悩んだ。(あくまで業務手続という体を守りつつ、実質1画面専用のAPI) がしかし、どうしてもパラメータが複雑になってしまう。 変なJSONにしてPHPとPOSTパラメータの周りをうろちょろするぐらいなら、 JSON親和性の高いうちに、クライアントでシンプルなAPIパラメータに変形してしまったほうが良いだろう。
・・・と思い、結局RestfulAPIで、クライアントにもりもりコードを持っていくスタイルを取った。 WebAPIのリクエストベースなテストも書きやすくなるしね。
しかし、Angularのテスト可用性が本当に死んでいる。 もともとリッチUIの予定だったので、打検はもともとだったが。。
Validation
HTMLのValidatorAPI
。ありゃだめだった、エラーメッセージが1つしか出ない。
おとなしくAngular
の$validations
なりフレームワークやライブラリに頼って、
ラベルか自分でポップアップするかしたほうがよさそう。
17/02/07雑記
ちょっと本格的にAngularを再開。
色々作りこんでいく中でいくつか悩みとアイディアが出たのでメモ。
RestAPIにするか否か
顧客管理のようなシステムを作っている。
顧客への「発送」業務があり、これは顧客によりあったりなかったりする。
データモデルがつまり 顧客
1 ― * 発送
という形になっている。
基本的にresource型のRestfulAPIを守ろうとしたが、 どうしてもブラウザ上で「顧客」を登録してから「発送」を登録することになる。
ただでさえ遠いWebサーバーに2往復もするのに加えて、 業務手続でできれば分離したいコードが、準コントローラーなコード中にむき出しになってしまう。 しかもこれは、1画面に1つ占有するコードみたいなもので、再利用が難しい。(思い切ってService化するのもアリだが)
Restじゃなくて、普通にWebAPI化しようとも悩んだ。(あくまで業務手続という体を守りつつ、実質1画面専用のAPI) がしかし、どうしてもパラメータが複雑になってしまう。 変なJSONにしてPHPとPOSTパラメータの周りをうろちょろするぐらいなら、 JSON親和性の高いうちに、クライアントでシンプルなAPIパラメータに変形してしまったほうが良いだろう。
・・・と思い、結局RestfulAPIで、クライアントにもりもりコードを持っていくスタイルを取った。 WebAPIのリクエストベースなテストも書きやすくなるしね。
しかし、Angularのテスト可用性が本当に死んでいる。 もともとリッチUIの予定だったので、打検はもともとだったが。。
Validation
HTMLのValidatorAPI
。ありゃだめだった、エラーメッセージが1つしか出ない。
おとなしくAngular
の$validations
なりフレームワークやライブラリに頼って、
ラベルか自分でポップアップするかしたほうがよさそう。
【JavaScript】ValidationAPIの標準エラーメッセージをフックして上書きする関数作った
GitHub
これで、Scriptトリガーの日本語英語切り替えが楽になる。
長さなどを文字列埋め込みできるようにメッセージをformatできるようにすればよかったけど、 Formatメソッド作らなきゃいけなくなるから削る。
【HTML】JavaScriptで検証結果のポップアップを呼び出す
ハマった。
デフォルトのValidationAPIはsubmitされないとポップアップしない?
<form id="f"> <input type="text" name="firstname" id="firstname" required> <button type="submit">submit</button> </form>
これをJavaScriptから
let elForm = document.getElementById('f'); elForm.submit();
したら、検証を無視してページ遷移が発生。
で、それっぽいAPIがあるんだけど、どれを見ても検証結果の true / falseを知ることができるだけで、検証結果のメッセージがポップアップしない。
if (elForm.checkValidatity()) { document.getElementById('error').innerText = ('エラーがあります。'); }
俺はデフォルトのあの動作が欲しいんだ。
とりあえずの解決法
function popupInvalided(elForm) { const fnSubmitHandler = (event) { event.preventDefault(); } let btn = document.createElement('button'); btn.setAttribute('type', 'submit'); btn.style.display = 'none'; elForm.addEventHandler(fnSubmitHandler); elForm.appendChild(btn); setTimeout(() => { btn.click(); setTimeout(() => { elForm.removeEventListener('submit', fnSubmitHandler); btn.remove(); }); }, 0); }
探したらポップアップするAPIあると思うんだけど。 これだけのためにW3C文書読む気になれない。
おまけ:setCustomValitiyの挙動
setCustomValidityで自由にエラー扱いにできるしエラーメッセージも動的に決められるが、 JavaScriptで空文字を再設定しない限り、ずっとその項目はエラーになり続ける。
// 書きかけたバグ if (!input.checkValidity()) { input.setCustomValidity('オリジナルのメッセージ'); }
回避策
- HTMLにtitleつけて回避する。
<input type="text" required title="名前は必須です。">
- setCustomValidityを使うところは、checkValidity()の前だけにする。
【Postgresql】トランザクション中、CURRENT_TIMESTAMPなどの値は固定
ハマった。
https://www.postgresql.jp/document/7.2/user/functions-datetime.html#FUNCTIONS-DATETIME-CURRENT
CURRENT_TIMESTAMP と、それに関連する関数はすべて現在のトランザクションが開始された時間を返すことを認識してください。とても重要なことです。この値はトランザクションが実行されている間に増加しません。とは言っても、timeofday() は実際の現在時間を返します。
代替として、clock_timestamp()
やtimeofday()
を使う。
【Java】JsoupのWhitelistは使わないほうがいい
前任者が残したコードが土壇場になって牙を剝いた。
Jsoupとは
Jsoupは、あいまいなHTMLでも確実に構文木にパースしてくれる高性能ライブラリ。
例えば<b>
とだけ書いても、<html><head></head><body><b></b></body></html>
まで補完してくれる。
あまつさえ、jQueryではないが、getElementByTagなどといったJavaScriptでおなじみのAPIみたいなものが使える。
Whitelistの罠
JsoupにはWhitelistクラスというフィルタールールみたいなものがあるが、結構罠を踏んだ。
- 単純なルールしか無理。「○○属性は必須だけど××は任意、その他全部禁止」とかできない。
- 致命的なのが、
<html>
、<body>
、<head>
は無条件でホワイトリストを通過すること。(任意の付きでも通過。XSSじゃん!)
2に関しては何か抜け道があると信じたいが、JsoupクラスのAPI見る限り期待できなさそう。 そもそも、厳格なルール付けには適していなさそう。
セキュアな実装をするならば、また他のHTMLパーサを探すか上記3タグについてメタいことをしたWhitelistを実装するしかない結論に至った所で帰った。