Skip to content

Commit 77de763

Browse files
committed
Merge pull request azu#44 from azu/connect
connect: サンプルの実装
2 parents ac15630 + c1bac2b commit 77de763

12 files changed

+255
-3
lines changed

.eslintrc

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
"semi": [
1616
2,
1717
"always"
18-
]
18+
],
19+
"no-console": 0
1920
},
2021
"env": {
2122
"es6": true,

.md.eslintrc

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
{
22
"rules": {
33
"no-undef": 0,
4-
"no-unused-vars": 0,
5-
"no-console": 0
4+
"no-unused-vars": 0
65
},
76
"plugins": [
87
"markdown"

SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
* [Introduction](ja/introduction/README.md)
55
* [jQuery](ja/jQuery/README.md)
66
* [ESLint](ja/ESLint/README.md)
7+
* [connect](ja/connect/README.md)
78

ja/connect/README.md

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Connect
2+
3+
> この文章はConnect 3.4.0を元に書かれています。
4+
5+
[Connect](https://github.com/senchalabs/connect "Connect")はNode.jsで動くHTTPサーバフレームワークです。
6+
_middleware_という拡張する仕組みを持っていて、connectが持つ機能自体はとても少ないです。
7+
8+
この章ではconnectの_middleware_の仕組みついて見て行きましょう。
9+
10+
## どう書ける?
11+
12+
Connectを使った簡単なEchoサーバを書いてみましょう。
13+
Echoサーバとは、送られてきたリクエストの内容をそのままレスポンスとして返すサーバのことです。
14+
15+
[import, connect-echo-example.js](../../src/connect/connect-echo-example.js)
16+
17+
このEchoサーバに対して、以下のようなリクエストBodyを送信すると、レスポンスとして同じ値が返ってきます。
18+
19+
```json
20+
{
21+
"key": "value"
22+
}
23+
```
24+
25+
`app.use(middleware)` という形で、_middleware_と呼ばれる関数には`request``response`といったオブジェクトが渡されます。
26+
そのため、リクエストみてフィルタリングしたり、任意のレスポンスを返したり出来るようになっています。
27+
28+
Echoサーバでは `req.pipe(res);` という形でリクエストをそのままレスポンスとして流す事で実現されています。
29+
30+
### middlewareをモジュールとして実装
31+
32+
もう少し_middleware_をプラグインらしくモジュールとして実装したものを見てみます。
33+
34+
次の[connect-example.js](#connect-example.js)では、あらゆるリクエストに対して、
35+
`"response text"`というレスポンスを`"X-Content-Type-Options"`ヘッダを付けて返すだけのものです。
36+
37+
それぞれの処理を_middleware_としてファイルを分けて実装し、`app.use(middleware)`で処理を追加しています。
38+
39+
[import errorHandler.js](../../src/connect/errorHandler.js)
40+
41+
[import nosniff.js](../../src/connect/nosniff.js)
42+
43+
[import hello.js](../../src/connect/hello.js)
44+
45+
[import connect-example.js](../../src/connect/connect-example.js)
46+
47+
基本的にどの_middleware_も`app.use(middleware)`という形で拡張でき、
48+
モジュールとして実装すれば再利用もしやすい形となっています。
49+
50+
> **Note** _middleware_となる関数の引数が4つであると、それはエラーハンドリングの_middleware_とするという、connectの独自のルールがあります。

package.json

+3
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,19 @@
3636
],
3737
"devDependencies": {
3838
"babel": "^5.8.23",
39+
"connect": "^3.4.0",
3940
"coveralls": "^2.11.4",
4041
"eslint": "^1.3.0",
4142
"eslint-plugin-markdown": "git://github.com/eslint/eslint-plugin-markdown.git",
4243
"espower-babel": "^3.3.0",
4344
"gitbook-cli": "^0.3.4",
4445
"gitbook-plugin-edit-link": "^1.4.1",
46+
"gitbook-plugin-include-codeblock": "^1.4.0",
4547
"gitbook-plugin-richquotes": "0.0.5",
4648
"gitbook-summary-to-path": "^1.0.1",
4749
"jsdom": "^6.3.0",
4850
"mocha": "^2.2.5",
51+
"node-fetch": "^1.3.2",
4952
"npm-run-all": "^1.2.8",
5053
"power-assert": "^1.0.0",
5154
"punctuate-coverage": "^1.0.3",

src/connect/connect-echo-example.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"use strict";
2+
import connect from "connect";
3+
import http from "http";
4+
import fetch from "node-fetch";
5+
import assert from "assert";
6+
var app = connect();
7+
// add Error handling
8+
app.use(function (err, req, res, next) {
9+
console.error(err.stack);
10+
res.status(500).send(err.message);
11+
next();
12+
});
13+
// request to response
14+
app.use(function (req, res) {
15+
req.pipe(res);
16+
});
17+
//create node.js http server and listen on port
18+
var server = http.createServer(app).listen(3000, request);
19+
20+
// request => response
21+
function request() {
22+
var closeServer = server.close.bind(server);
23+
var requestBody = {
24+
"key": "value"
25+
};
26+
fetch("http://localhost:3000", {
27+
method: "POST",
28+
body: JSON.stringify(requestBody)
29+
})
30+
.then(res => res.text())
31+
.then(text => {
32+
assert.deepEqual(text, requestBody);
33+
}).then(closeServer, closeServer);
34+
}

src/connect/connect-example.js

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"use strict";
2+
import errorHandler from "./errorHandler";
3+
import hello from "./hello";
4+
import nosniff from "./nosniff";
5+
import assert from "assert";
6+
import connect from "connect";
7+
import http from "http";
8+
import fetch from "node-fetch";
9+
const responseText = "response text";
10+
var app = connect();
11+
// add Error handling
12+
app.use(errorHandler());
13+
// add "X-Content-Type-Options" to response
14+
app.use(nosniff());
15+
// respond to all requests
16+
app.use(hello(responseText));
17+
//create node.js http server and listen on port
18+
var server = http.createServer(app).listen(3000, request);
19+
20+
function request() {
21+
var closeServer = server.close.bind(server);
22+
fetch("http://localhost:3000")
23+
.then(res => res.text())
24+
.then(text => {
25+
assert.equal(text, responseText);
26+
server.close();
27+
})
28+
.catch(console.error.bind(console))
29+
.then(closeServer, closeServer);
30+
}

src/connect/echo.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
"use strict";
2+
export default function () {
3+
return function (req, res) {
4+
req.pipe(res);
5+
};
6+
}

src/connect/errorHandler.js

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
"use strict";
2+
export default function errorHandler() {
3+
return function (err, req, res, next) {
4+
console.error(err.stack);
5+
res.status(500).send(err.message);
6+
next();
7+
};
8+
}

src/connect/hello.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
"use strict";
2+
export default function (text) {
3+
return function (req, res) {
4+
res.end(text);
5+
};
6+
}

src/connect/nosniff.js

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"use strict";
2+
function setHeaders(res, headers) {
3+
Object.keys(headers).forEach(key => {
4+
let value = headers[key];
5+
if (value !== null) {
6+
res.setHeader(key, value);
7+
}
8+
});
9+
}
10+
export default function () {
11+
return function (req, res, next) {
12+
setHeaders(res, {
13+
"X-Content-Type-Options": "nosniff"
14+
});
15+
next();
16+
};
17+
}

test/connect/hello-test.js

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// LICENSE : MIT
2+
"use strict";
3+
import assert from "power-assert";
4+
import connect from "connect";
5+
import errorHandler from "../../src/connect/errorHandler";
6+
import nosniff from "../../src/connect/nosniff";
7+
import hello from "../../src/connect/hello";
8+
import echo from "../../src/connect/echo";
9+
import http from "http";
10+
import fetch from "node-fetch";
11+
describe("connect", function () {
12+
var responseText = "test";
13+
var server;
14+
describe("errorHandler", function () {
15+
beforeEach(function (done) {
16+
var app = connect();
17+
app.use(errorHandler());
18+
app.use((req, res, next) => {
19+
next(new Error("wrong"));
20+
});
21+
server = http.createServer(app).listen(3000, done);
22+
});
23+
afterEach(function () {
24+
server && server.close();
25+
});
26+
it("should return 500 status response", function () {
27+
return fetch("http://localhost:3000")
28+
.then(res => res.status)
29+
.then(status => {
30+
assert(status, 500);
31+
});
32+
});
33+
34+
});
35+
describe("hello", function () {
36+
beforeEach(function (done) {
37+
var app = connect();
38+
app.use(errorHandler());
39+
app.use(hello(responseText));
40+
server = http.createServer(app).listen(3000, done);
41+
});
42+
afterEach(function () {
43+
server && server.close();
44+
});
45+
it("should return response text", function () {
46+
return fetch("http://localhost:3000")
47+
.then(res => res.text())
48+
.then(text => {
49+
assert.equal(text, responseText);
50+
});
51+
});
52+
});
53+
describe("sniff", function () {
54+
beforeEach(function (done) {
55+
var app = connect();
56+
app.use(nosniff());
57+
app.use(hello(responseText));
58+
server = http.createServer(app).listen(3000, done);
59+
});
60+
afterEach(function () {
61+
server && server.close();
62+
});
63+
it("should return response has `X-Content-Type-Options` header", function () {
64+
return fetch("http://localhost:3000")
65+
.then(res => {
66+
assert.equal(res.headers.get("x-content-type-options"), "nosniff");
67+
});
68+
});
69+
});
70+
describe("echo", function () {
71+
beforeEach(function (done) {
72+
var app = connect();
73+
app.use(echo());
74+
server = http.createServer(app).listen(3000, done);
75+
});
76+
afterEach(function () {
77+
server && server.close();
78+
});
79+
it("should return request as response", function () {
80+
var requestBody = {
81+
key: "value"
82+
};
83+
return fetch("http://localhost:3000", {
84+
method: "POST",
85+
headers: {
86+
"Accept": "application/json",
87+
"Content-Type": "application/json"
88+
},
89+
body: JSON.stringify(requestBody)
90+
}).then(res => {
91+
return res.json();
92+
}).then(json => {
93+
assert.deepEqual(json, requestBody);
94+
});
95+
});
96+
});
97+
});

0 commit comments

Comments
 (0)