Expressフレームワークの基本的な使い方(Node.jsその2)

Expressフレームワークの基本的な使い方(Node.jsその2)

Express は、Web アプリケーションとモバイル・アプリケーション向けの一連の堅固な機能を提供する最小限で柔軟な Node.js Web アプリケーション・フレームワークです

https://expressjs.com/ja/
目次
  1. 初期設定とExpressのインストール
  2. ルーティング処理
  3. 静的ファイルの返却
  4. 動的ファイルの返却
  5. ミドルウェアについて
  6. Express Generator

初期設定とExpressのインストール

プロジェクトフォルダを作り、package.json作成
*エントリーポイントは、index.jsから、慣例的に使われているapp.jsに変更します

npm init -y

「.env」ファイルを作り環境変数を設定します
*GitHubのパブリックに上げる場合などは、「.envファイル」は、「.gitignore」に追加してリモートにpushしないファイルとして指定します

備考:Node.jsにおける環境変数の利用について
デプロイによって設定が異なる場合、APIキーや、データベースの設定などは、本番環境と開発環境では異なる設定を使うことが多く、直接ハードコーディングするのではなく、環境変数を利用します
OSがプログラムの実行時などに必要となる「利用者やコンピュータごとに内容が異なる設定値」を環境変数に保存します
環境変数はprocess.envオブジェクトに格納されます

Node.jsで定義済み又は慣例的に決まっている環境変数
コードで利用(例:process.env.NODE_PATH)
実行する(例:NODE_ENV=production node && node index.js)

変数名説明
NODE_PATH「;」で分割されたディレクトリパスリストを指定して、モジュール検索先を指定
NODE_ENV‘production’ または ‘development’ を指定する
NODE_DEBUGデバッグ出力したいモジュール名をカンマ区切りで指定します

任意で:VSCodeのデバッグ構成(launch.json)

  1. デバッグしたいファイルを開いて、左横のアイコン「実行とデバッグ」をクリックします
  2. 「launch.jsonファイルを作成します」をクリックします
  3. 「Node.js」を選択します
  4. launch.jsonファイルに”envFile”も追加します(.envがあるとき)

“program”はデバッグ実行時に起動するプログラムのパスを指定します

"program": "${workspaceFolder}/app.js",
"envFile": "${workspaceFolder}/.env"

任意で:ブロジェクトにESLintを設定する
*VSCodeのESLintプラグインはインストール済み

$ npm install eslint --save-dev

#ウィザードに沿って設定ファイルを作成します。
$ npx eslint --init

作成された.eslintrc.js"extends": "eslint:recommended"(推奨のルール)と必要に応じて、"rules": {}を追加します
個人的にconsoleは使いたいので

module.exports = {
    "env": {
        "browser": true,
        "commonjs": true,
        "es2021": true,
        "node": true
    },
    "extends": "eslint:recommended",
    "parserOptions": {
    "ecmaVersion": 12
    },
    "rules": {
        "no-console": "off"
    }
};

Expressのインストール

npm install express --save

app.jsファイルを作成

ターミナルからnode app.jsを実行した、ブラウザからlocalhost:3000(127.0.0.1:3000)にアクセスするとHello Worldが表示されます
app.listenがサーバー起動処理で、app.listenの第一引数はポート番号の指定です

// Expressサーバーパッケージを読み込み
const express = require("express");
const app = express();

//ルーティング
app.get("/", (request, response) => {
  response.end("Hello World");
});

// Expressサーバー起動 3000はポート
app.listen(3000, () => {
  console.log('3000ポートでサーバー起動');
});

nodemonをインストールします
nodemonはデフォルトでプロジェクトフォルダ内の全JavaScriptファイルやJSONファイル(node_modulesフォルダは除く)を監視して、コードを変更して保存するたびにサーバーアプリケーションが自動で再起するようにします

nodemonは、ディレクトリ内のファイルの変更が検出された場合にnodeアプリケーションを自動的に再起動することで、node.jsベースのアプリケーションの開発を支援するツールです。

nodemonはコードや開発方法に追加の変更を必要としません。nodemonを使用するには、スクリプトを実行する際にコマンドラインでnodeという単語を置き換えてください。

npm install nodemon --save-dev

package.jsonのscriptsセクションに登録されているstartコマンドの内容を以下のように書き換えます
npm start(コードを変更するたびにサーバー起動する必要がなくなります)

"scripts": {
  "start": "nodemon app.js"
},

*現在は npmでインストール時の –saveは不要ですが、念の為^^;

Webサーバーはクライアントから送られてくるリクエストを受け付け、クライアントへレスポンスを返却します

ルーティング処理

リクエストに対して、処理を振り分けします

METHOD:リクエストメソッドを指定(get・post ・put・ delete)
PATH : URLルーティングを指定(正規表現にすることができます)
参考:https://expressjs.com/ja/guide/routing.html
コールバック関数 : PATHにマッチしたときの動作を指定(レスポンスに何を返すか等)

app.METHOD(PATH, コールバック関数)

備考
コールバック関数(関数の引数に渡す関数)、現在実行している処理とは異なるタイミングで実行されます(非同期処理)
(ネットワーク通信やファイルの読み書きなど)時間がかかる処理は、キュー(関数実行の待ち行列)に非同期で実行したい関数として登録し、自身は次の処理に進みます
非同期処理にはコールバック関数が引数として指定されていたり、Promise形式で処理結果を返す場合などがあります

requestはブラウザからのリクエストに関するオブジェクト
responseはブラウザに返すレスポンスに関するオブジェクトです

// ルーティング設定
app.get('/', (request, response) => {
  
});

responseメソッド
responseオブジェクトのメソッドは、レスポンスをクライアントに送信し、リクエストとレスポンスのサイクルを終了します

  • response.download() :ファイルのダウンロードのプロンプトを出します
  • response.end() :レスポンスプロセスを終了します
  • response.json() :JSON レスポンスを送信します
  • response.jsonp() :JSONP をサポートする JSONレスポンスを送信します
  • response.redirect(): リクエストをリダイレクトします
  • response.render() :ビュー・テンプレートをレンダリングします
  • response.send() :さまざまなタイプのレスポンスを送信します
  • response.sendFile :ファイルを送信します
  • response.sendStatus() :レスポンスのステータスコードを設定し、レスポンス本文として送信します

パスパラメーター
URLパス指定の際に「:(コロン)」に続けて任意の文字列を指定すると、その指定した文字列にあたる部分のパスの内容がrequest.paramsオブジェクトのプロパティとして登録された状態でルーティング処理に入ります
プロパティの名前は、URLパス指定の際に「:(コロン)」に続けて指定した文字列となります
request.params.idというプロパティが登録されます

app.get('/blog/:id', (request, response) => {
   console.log(request.params.id)
});

クエリパラメーター
GETリクエストの際に、urlの末尾に「?」に続くキーと値「key=val」形式のデータですが、?以降パラメーターはルーティングのパスには影響を与えません(無視されます)
(例:http://127.0.0.1:3000/blog/?page=3)
値を取得するには

request.query.key(キー名)

備考
複数のURLパラメータを送信する場合は?page=3&hoge=valのように&で繋げます
日本語のようなマルチバイト文字列を送信する場合はURLエンコードで「%と英数字」だけで構成された文字列に変換してURLパラメータに指定します
ちなみに、POSTパラメータの解析には、以前はbody-parserのインストールが必要でしたが、Expressバージョン4.16.0からはexpress.urlencodedで解析できます
POSTリクエストでは、request.queryではなくrequest.bodyに入ります

静的ファイルの返却

ファイルをそのままレスポンスとして返却します

express.static関数の戻り値のミドルウェアを利用します
*ミドルウェアの詳細は後で

express.static(root, [options])

プロジェクトフォルダ内にpublicフォルダを作成します

ブラウザから静的ファイル(CSSやJavaScriptや画像など)へのアクセスがあった場合に、publicフォルダを検索して見つかった場合はファイルの中身を返すようにします
*publicフォルダから相対的なファイルを検索するため、publicはURLの一部に含まれません
例:http://localhost:3000/css/style.css

app.use(express.static('public'));

express.static関数でURLの一部プレフィックス(hoge)を作成する
例:http://localhost:3000/hoge/css/style.css
*express.static関数に指定するパスは、プロセスを起動するディレクトリに対して相対的です
別のディレクトリから実行する場合は、絶対パスを使用する方が安全です

const path = require("path");

app.use('/hoge', express.static(__dirname + '/public'));

第二引数の [options]について

動的ファイルの返却

HTMLファイル(HTMLの雛形)にソースコードを埋め込み、HTMLファイルを生成して、レスポンスとして返却します

テンプレートエンジン(EJS)設定します
*テンプレートエンジンにはその他、PugやJadeなどがあります

npm install ejs --save

プロジェクトフォルダ内にviewsフォルダを作り、その中にindex.ejsファイルを作成

指定したテンプレートエンジンはExpressの内部で必要な時に自動的にrequireするので、別途をrequireする必要はありません
response.renderの第二引数に渡したオブジェクトの内容は、テンプレート内で実行するJavaScriptから参照できます
第一引数は、テンプレートファイルのパス(viewsからの相対パス)です

app.set('view engine', 'ejs');

app.get('/', (request, response) => {
  response.render('./index.ejs')
});
//第二引数がテンプレートに渡すデータ
response.render(path,data)

テンプレートの基本構文

  • <% ~ %>はJavaScriptコードを実行
  • <%= ~ %>は値の出力(エスケープ処理あり)
  • <%- ~ %>は値の出力(エスケープ処理なし)
    *基本的にはインクルードに限定して使う
  • <%# ~ %>はコメント

include()を使い、共通する部分のファイルを切り出し、切り出したファイルをテンプレートで読み込んで利用出来ます
第一引数:インクルードしたいテンプレートのファイルパス(拡張子の「.ejs」は省略できる)
第二引数:インクルードするテンプレートに引き渡すデータ
戻り値は、生成されたHTML

<%- include('./_partial', {param:'param'}) %>

app.localsオブジェクトに登録された値や関数は、テンプレートから参照できます

app.locals.title = 'My App'

console.log(app.locals.title)
//  'My App'

テンプレートエンジンで使える値や関数を渡す
ちなみに res.render(path,data)のdataは locals.dataと同じ

res.locals.method =()=>{}

ミドルウェアについて

Expressはリクエストのルーティングとレスポンスの整形をします
ミドルウェアは、リクエストやレスポンスに追加処理をする関数です

ミドルウェア関数
next() 関数は次の処理を呼ぶために必要です

function (req, res, next) {
 // 次の処理を呼ぶためのnext()
  next()
}

//エラー処理がある場合
function ( err, req, res, next) {
 // 次の処理を呼ぶためのnext()
  next()
}

ミドルウェアはapp.useに引き渡して利用します
*全てのリクエストに対して処理されます

app.use(function (req, res, next) {
 // 処理内容
  next()
})

/user/:idのパスにミドルウェアの関数をマウントしています。
/user/:id パス上のリクエストに対して実行されます

app.use('/user/:id', function (req, res, next) {)
  // 処理内容
  next()
})

ミドルウェアを書く場所は重要です
上から順番に実行されます

express.Router
機能単位でルーターをモジュールとして作成しミドルウェアとして使います
router.use()でルーターレベルのミドルウェアをロードします

ルーターファイルを作成します(routes/index.js)

const express = require('express')
//ルーティング処理用のオブジェクトを作成
const router = express.Router()

//useからの相対パスになるので この場合はhome/index
router.get('/index', (req, res) => {
   response.render('./index.ejs')
})
module.exports = router;
//app.jsに追加
//切り出したrouterを読み込みますrequire('./routes/index.js')
app.use('/home', require('./routes/index.js'))

Express Generator

express-generator を使うとスケルトンを素早く作成できます

npm i express-generator -g

expressコマンドを使えるようにります(オプションで、ejs・hbs・pugの指定などが出来ます)

ディレクトリー構造は

.
├── app.js
├── bin
│   └── www
├── package.json
├── public
│   ├── images
│   ├── javascripts
│   └── stylesheets
│       └── style.css
├── routes
│   ├── index.js
│   └── users.js
└── views
    ├── error.pug
    ├── index.pug
    └── layout.pug