Skip to content

Instantly share code, notes, and snippets.

@Jxck
Created August 20, 2012 10:30
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save Jxck/3402936 to your computer and use it in GitHub Desktop.
Save Jxck/3402936 to your computer and use it in GitHub Desktop.
REST と WebSocket
# REST と WebSocket
t_wada さんとちょっと話す機会があったので、ここまでに考えてたことを一旦まとめて見たいと思う。
REST については、「Web を支える技術」でお茶を濁さず、本家論文なども参照されたし。
## REST
REST はプロトコルでもアーキテクチャでもなく、アーキテクチャスタイルです。
そこにはいくつかの原則があり、最も重要な原則の一つにステートレス性があります。
[REST#原則(wikipedia)](http://ja.wikipedia.org/wiki/REST#.E5.8E.9F.E5.89.87)
この原則は Cookie を用いたセッションの実現すら本質的には否定します(ただし、事実上禁止はしないけど)。
このステートレス性が、分散システムである Web の成功の秘訣だったし、
ステートレスだったからこそ、URL/Method/query などに必要十分な情報を持たせた。
「ステートレスは一番最初に捨てられる原則ではないか?」
そうかもしれない。しかし、現状そこを考えた例は少ないのでは。
## WebSocket
生の WebSocket は大体こんな感じ。
[WebSocket サーバの実装とプロトコル解説](http://d.hatena.ne.jp/Jxck/20120725/1343174392)
```javascript
// Client
var ws = new WebSocket("ws://example.com/");
ws.onopen = function() {
ws.send("test");
ws.onmessage = function(message) {
console.log(message.data); // test
};
}
```
WS オブジェクトを作るとき URL を渡している。
これは、確かにリソースではある。しかし、コネクションを確立しにいく対象で、
レスポンスとしては WS コネクションが返って来るととることも出きるかもしれないけど、
そっから先のやりとりについて、この URL 表現は関与できない。
# Socket.IO
純粋な WS は十分に低レベルな API なので、
そのままではイベントを使い分けたりができない。
よって、その上に独自でプロトコルを組む余地は大きい。
Socket.IO はその一例(Socket.IO プロトコルを独自に定義している)。
[Socket.IO API 解説](http://d.hatena.ne.jp/Jxck/20110730/1312042603)
```javascript
// Client
var socket = io.connect('http://example.com');
socket.on('connect', function() {
socket.emit('msg send', 'data');
socket.on('msg push', function (msg) {
console.log(msg);
});
});
```
# REST over Socket.IO?
Socket.IO のように自分でプロトコルとその API を提供するライブラリを作れば、
下記のようなこともできる。
これが、多くの人が「WebSocket に REST を持ち込む」と考えた場合、
最初に思いつくものなのではないか?
[flatiron/socketful](https://github.com/flatiron/socketful#core-socketio-mappings)
```javascript
socket.emit('creatures', 'create', { id: 'bob' } , function(err, bob) {
console.log('created: ', bob);
};
```
しかし、WebSocket で確立したコネクション上では、
基本的に message のやりとりしか行っていない。
(HTTP でいう Body 相当)
Body に工夫をするのは WebSocket 上の独自サブプロトコルでしかない
# WebSocket の本質
WebSocket の本質は
```
server push
```
接続こそクライアントからだが、その後はサーバから Push 可能。
そして、サーバもクライアントから Push を受け取っている状態とも考えられる。
(HTTPとは違うコンテキストで)
だから「双方向(bi-directional)」。
# WebSocket は REST の夢をみるか?
レイヤが違う
# WebSocket は REST を夢にみるか?
Web は 論文の共有なんかをモチベーションに始まった。
ドキュメントは Pull するものだった。
それを根底として、色々積み上げてきた
HTTP のアーキテクチャにおいて、 REST は親和性が高かった。
でも、Push が可能になった時点で、
「アーキテクチャは延長ではなく変化」を迎えた。
REST を無理やり当てはめるより、積極的に別の方法を模索したっていいんじゃない?
# 「Web が壊れる」のか?
wget で取得できない Web は壊れてる的なあれについて。
気持ちはわかるけど、そこで壊れてるのは、
「Web」ではなく「ドキュメント」だと思う。
リソース表現としてのドキュメントが、
URI, Method で取得できないと、
それを壊れてると言いたいのはわかる。
たぶん。「Web がドキュメントだけじゃなくなった」
と考えれば自然なんじゃないかと思う。
つまり、いままで HTTP の「レスポンスボディ」の中で
「ドキュメント」形式で表現されていた「リソース」だけじゃなくて、
もっと別の形の「何か」を Web は扱えるようになったと
考えるのはどうだろう。
というか、 WS はそもそも HTTP ではできなかったことを、
出来るようにしてしまったんだから、
そこから得られる結果が、今までと全く変わってしまうのは、
当然だと思う。
# リソースからストリームへ
その、「何か」を自分は「ストリーム」と
捉えたら面白そうだと思ってる。
自分の模索過程
http://d.hatena.ne.jp/Jxck/20111223/1324659260
https://gist.github.com/Jxck/stream.io
- WebSocket によって扱えるデータはストリームという単位で抽象化可能と考える
- ストリームは実装レベルでは Node.js の Stream という API を基準に考えているけど、たぶん汎用化可能。
- ストリームは基本的に2種類
- Readable Stream
- Writable Stream
また、これを接続するために pipe という API を考える。
## Readable Stream(RStrm)
読み取り可能で、接続していればどんどんデータがやってくるストリーム。
データの発生がイベントとして pipe してるストリームに通知される。
水道の蛇口みたいなイメーじ。
ex) tail -f, twitter stream, stdin etc
## Writable Stream(WStrm)
データをどんどん書き込むことができるストリーム。
バケツのようなイメージ
ex) DB, File, stdout etc
## pipe
WStrm と RStrem を繋ぐもの。
UNIX の pipe(|) と同じイメージ。
```javascript
WStrm.pipe(RStrm);
```
## 例
```
蛇口から水を組みたい人は、自分のバケツにパイプを繋ぐ。
```
### tail -f を画面に垂れ流す管理アプリ
tail -f を RStrm として抽象化。
DOM(つまり画面) を WStrm として抽象化。
2つを pipe で繋ぐ。
tail -f されたデータがサーバからどんどん push されていく。
```javascript
// server
tailf.pipe(client);
````
```javascript
// client
tailf.pipe(client);
````
### twitter streaming
twitter は twitter stream を WebSocket を用いた ReadableStream として公開する。
twitter stream を読みたい人はなんらかの WritableStream を用意して pipe しにいく。
pipe しにいくのはだれでも良い。
たとえば Google の bot も、そのデータを pull しにいくのではなく
push してもらいにいくために ReadableStream としてリアルタイムなデータを収集できるのでは。
## Chat
クライアント(RStrm) -> サーバ(WStrm/RStrm) -> クライアント(WStrm)
よくある双方向チャット。
## アーキテクチャはある。が、そこにアーキテクチャスタイルはあるか。
t_wada さんが指摘する、時間を超えて合意を形成できる設計指針であるところの
「アーキテクチャスタイル」は WebSocket などを用いて実装するリアルタイムな Web
には、今のところ存在しない。
まずは best practice/bad know how などを始めに自然発生的に少しづつ出てくるだろうという
t_wada さんの考えには同意。
ざっとこんな感じ。正直まだ固まってない。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment