Skip to content

Commit d14ddf5

Browse files
committed
Merge pull request #65 from azu/connect-like
Connect likeの実装
2 parents d679c5d + 69d334e commit d14ddf5

File tree

7 files changed

+147
-9
lines changed

7 files changed

+147
-9
lines changed

ja/connect/README.md

+21-4
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,13 @@ Echoサーバでは `req.pipe(res);` という形でリクエストをそのま
3636

3737
それぞれの処理を_middleware_としてファイルを分けて実装し、`app.use(middleware)`で処理を追加しています。
3838

39-
[import errorHandler.js](../../src/connect/errorHandler.js)
4039

4140
[import nosniff.js](../../src/connect/nosniff.js)
4241

4342
[import hello.js](../../src/connect/hello.js)
4443

44+
[import errorHandler.js](../../src/connect/errorHandler.js)
45+
4546
[import connect-example.js](../../src/connect/connect-example.js)
4647

4748
基本的にどの_middleware_も`app.use(middleware)`という形で拡張でき、
@@ -66,9 +67,9 @@ Connectが登録された_middleware_をどう処理するかというと、
6667

6768
上記の例だと以下の順番で_middleware_が呼び出されることになります。
6869

69-
- errorHandler
7070
- nosniff
7171
- hello
72+
- errorHandler
7273

7374
エラーハンドリングの_middleware_は処理中にエラーが起きた時のみ呼ばれます。
7475

@@ -110,6 +111,22 @@ Rackを参考にして実装されています。
110111

111112
- [Ruby - Rack解説 - Rackの構造とRack DSL - Qiita](http://qiita.com/higuma/items/838f4f58bc4a0645950a#2-5 "Ruby - Rack解説 - Rackの構造とRack DSL - Qiita")
112113

113-
次は、先ほど抽象的なコードとなっていたものを、具体的な実装にしていきます。
114+
次は、先ほど抽象的なコードとなっていたものを具体的な実装にしながら見ていきます。
115+
116+
## 実装してみよう
117+
118+
`Junction`というConnectライクな_middleware_をサポートしたものを作成してみます。
119+
120+
`Junction`は、`use(middleware)``process(value, (error, result) => { });`を持っているシンプルなクラスです。
121+
122+
[import junction.js](../../src/connect/junction.js)
123+
124+
実装を見てみると、`use`で_middleware_を登録して、`process`で登録した_middleware_を順番に実行していきます。
125+
そのため、`Junction`自体は渡されたデータは何も処理せずに、_middleware_との中継のみをしています。
126+
127+
登録する_middleware_はConnectと同じで、処理をしたら`next`を呼んで、次の_middleware_が処理するというのを繰り返しています。
128+
129+
使い方はConnectと引数の違いはありますが、ほぼ同じような形で利用できます。
130+
131+
[import junction-example.js](../../src/connect/junction-example.js)
114132

115-
## 実装してみよう

src/connect/errorHandler.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
"use strict";
22
export default function () {
33
return function errorHandling(err, req, res, next) {
4-
console.error(err.stack);
5-
res.status(500).send(err.message);
4+
res.writeHead(404);
5+
res.write(err.message);
6+
res.end();
67
next();
78
};
89
}

src/connect/junction-example.js

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"use strict";
2+
import Junction from "./junction";
3+
import assert from "assert";
4+
let junction = new Junction();
5+
junction.use(function toUpperCase(res, next) {
6+
res.value = res.value.toUpperCase();
7+
next();
8+
});
9+
junction.use(function exclamationMark(res, next) {
10+
res.value = res.value + "!";
11+
next();
12+
});
13+
junction.use(function errorHandling(error, res, next) {
14+
console.error(error.stack);
15+
next();
16+
});
17+
18+
let text = "hello world";
19+
junction.process(text, function (error, result) {
20+
if (error) {
21+
console.error(error);
22+
}
23+
let value = result.value;
24+
assert.equal(value, "HELLO WORLD!");
25+
});

src/connect/junction.js

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"use strict";
2+
function isErrorHandingMiddleware(middleware) {
3+
// middleware(error, text, next)
4+
let arity = middleware.length;
5+
return arity === 3;
6+
}
7+
function applyMiddleware(error, response, middleware, next) {
8+
let errorOnMiddleware = null;
9+
try {
10+
if (error && isErrorHandingMiddleware(middleware)) {
11+
middleware(error, response, next);
12+
} else {
13+
middleware(response, next);
14+
}
15+
return;
16+
} catch (error) {
17+
errorOnMiddleware = error;
18+
}
19+
// skip the middleware or Error on the middleware
20+
next(errorOnMiddleware, response);
21+
}
22+
23+
export default class Junction {
24+
constructor() {
25+
this.stack = [];
26+
}
27+
28+
use(middleware) {
29+
this.stack.push(middleware);
30+
}
31+
32+
process(initialValue, callback) {
33+
let response = {value: initialValue};
34+
let next = (error) => {
35+
let middleware = this.stack.shift();
36+
if (!middleware) {
37+
return callback(error, response);
38+
}
39+
applyMiddleware(error, response, middleware, next);
40+
};
41+
next();
42+
}
43+
}

test/connect/hello-test.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,20 @@ describe("connect", function () {
1414
describe("errorHandler", function () {
1515
beforeEach(function (done) {
1616
let app = connect();
17-
app.use(errorHandler());
1817
app.use((req, res, next) => {
1918
next(new Error("wrong"));
2019
});
20+
app.use(errorHandler());
2121
server = http.createServer(app).listen(3000, done);
2222
});
2323
afterEach(function () {
2424
server && server.close();
2525
});
26-
it("should return 500 status response", function () {
26+
it("should return 404 status response", function () {
2727
return fetch("http://localhost:3000")
2828
.then(res => res.status)
2929
.then(status => {
30-
assert(status, 500);
30+
assert(status, 404);
3131
});
3232
});
3333

test/connect/junction-test.js

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// LICENSE : MIT
2+
"use strict";
3+
import assert from "power-assert";
4+
import Junction from "../../src/connect/junction";
5+
describe("junction", function () {
6+
context("when register middlewares", function () {
7+
it("should connect middleware, the order is register", function (done) {
8+
let junction = new Junction();
9+
junction.use(function errorHandling(error, text, next) {
10+
next(error);
11+
});
12+
junction.use(function toUpper(res, next) {
13+
res.value = res.value.toLocaleUpperCase();
14+
next();
15+
});
16+
junction.use(function addDesu(res, next) {
17+
res.value += " suffix";
18+
next();
19+
});
20+
junction.process("text", (error, result) => {
21+
if (error) {
22+
return done(error);
23+
}
24+
assert.equal(result.value, "TEXT suffix");
25+
done();
26+
});
27+
});
28+
});
29+
context("when occur error in middleware", function () {
30+
it("should call errorHandling middleware", function (done) {
31+
let junction = new Junction();
32+
junction.use(function toUpper(res) {
33+
throw new Error("error on " + res);
34+
});
35+
junction.use(function errorHandling(error, res, next) {
36+
assert(error instanceof Error);
37+
assert.equal(res.value, "text");
38+
next();
39+
});
40+
junction.process("text", (error, res) => {
41+
if (error) {
42+
return done(error);
43+
}
44+
assert.equal(res.value, "text");
45+
done();
46+
});
47+
});
48+
});
49+
});

test/prh-rule.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,6 @@ rules:
7272
pattern:
7373
- プラグイン機構
7474
- プラグインのアーキテクチャ
75+
- expected: middleware
76+
pattern:
77+
- ミドルウェア

0 commit comments

Comments
 (0)