expressを使い始めて一体バックエンドで行われているのか不思議に思ったので調べてみました。
そもそも、httpリクエストやhttpレスポンスが何なのかを理解しなくてもアプリを作成出来ればよいはずなんだけど、理解しないと複雑なルーティングやリクエストやレスポンスを引き継いだり受け渡したりしないと作り上げられないという現実にぶち当たる・・・ので避けては通れないし、避け続けているとスキルアップしない、モチベーションの低下、退場となりかねないので、素人なりに分かるところまでやってみます!
まずはexpressのデフォルトを立ち上げてapp.js
にあるこの部分。
varexpress=require('express');//2行目varapp=express();//10行目
ここでまず混乱したのはroutes/index.js:1:2
にある
var express = require('express');
var router = express.Router();
との整合性。検索してサイトの例でよく見る
app.get("/", (req, res) => {
res.status(200).send("OK");
});
のような記載。変数appにgetやpost, put, deleteを付けるんならワザワザrouter = express.Router();
としなくてもイイんじゃね?と・・・もっと言うとappとrouterで何が違うの?ってなった。
すぐに、app.get()
はrouter.get()
の簡略化してサンプルを作成していると理解出来ます。app.js
はアプリケーションを起動するためにあって個別の細々した機能はそれぞれ別ファイルに書くべき、そのためにexpressのメソッドとしてRouterが独立している。
では、ドキュメントでそのあたり確認してみましょう!
Express APIリファレンスのナビゲーションウィンドウのRouterの説明文に
You can think of it as a “mini-application,” capable only of performing middleware and routing functions.
関数であること、よりわかりやすく'ミニアプリケーション'と記載されてます。(記載はしませんがapp側にはtop-levelとなっています)
これで、変数appで利用されるroutingと変数routerのそれがほぼ同じ役割、使い分けするためだけに分けているということが分かります。
もっと言うと、変数appがアプリケーション本体、変数routerはミニアプリケーションという階層構造になっていることも分かります。
では、expressのソースコードでも確認しましよう!
//application.js
var Router = require('./router'); //17行目
var methods = require('methods'); //methodsってなんだ?
var middleware = require('./middleware/init');
router.jsをrequireしていますね。反対にrouter.jsには反対のrequireはないので階層構造になっています。
さて、もう少し突っ込んでみます。では、app.get()
やrouter.post()
の第2引数のコールバック関数で何でreq, res, next
を指定してるの?っていう疑問に進みます。いや、そんなの分かるに決まってるやん!とか、そのまま型として覚えておけばイイんだよ、とか、言われそうですが、疑問に思ったもんは仕方ありません。
router.get('/', function (req, res) { //app.getでも構わない
res.send('hello world')
})
これですね。第1引数がエンドポイント、第2引数がコールバック(コールバックについてはまた詳しくやりたいですが、今のところは関数内の関数くらいに思っておいてください)で、何を指定出来るのか、まずはリファレンスを見てみます。
.middleware function.
.series of middleware functions (separated by commas).
.An array of middleware functions.
.combination of all of the above.
となってます。取り敢えず、ミドルウェア関数ならカンマで繋げればどんなけでもつなげることが出来ると分かります。でも知りたいのはfunction(req, res)
の部分。
色々調べて結果、ここに行き着きました。
//lib/routers/layer.js
function Layer(path, options, fn) {
if (!(this instanceof Layer)) {
return new Layer(path, options, fn);
}
debug('new %o', path)
var opts = options || {};
this.handle = fn;
this.name = fn.name || '<anonymous>';
this.params = undefined;
this.path = undefined;
this.regexp = pathRegexp(path, this.keys = [], opts);
// set fast path flags
this.regexp.fast_star = path === '*'
this.regexp.fast_slash = path === '/' && opts.end === false
}
おじさん、このあたりが`function(req, res)を書いているように思うんだ・・・・
未完