Express チュートリアル Part 2: スケルトン Web サイトの作成 - ウェブ開発を学ぶ

Express チュートリアル Part 2: スケルトン Web サイトの作成
========================================

* 前のページ
* Overview: Express Nodejs
* 次のページ

この Express チュートリアルの 2 回目の記事では、どのようにして "スケルトン" Web サイトプロジェクトを作成し、サイト固有のルート、テンプレート/ビュー、およびデータベース呼び出しを追加するかを説明します。

| 前提条件: | Node 開発環境を設定します。Express チュートリアルを確認してください。 |
| --- | --- |
| 目標: | Express Application Generator を使用して独自の新しい Web サイトプロジェクトを開始できるようにする。 |

概要
--

この記事では Express Application Generator ツールを使用して "スケルトン" Web サイトを作成する方法を説明します。このツールには、サイト固有のルート、ビュー/テンプレート、およびデータベース呼び出しを追加できます。この場合は、このツールを使用してローカルライブラリ Web サイト用のフレームワークを作成し、後でそのサイトに必要な他のすべてのコードを追加します。プロセスは非常に単純で、必要に応じてサイトのテンプレートエンジンと CSS ジェネレータを指定して、新しいプロジェクト名を指定してコマンドラインでジェネレータを呼び出すだけです。

次のセクションでは、アプリケーションジェネレータを呼び出す方法を示し、さまざまな ビュー/CSS オプションについて簡単に説明します。また、スケルトン Web サイトの構造についても説明します。最後に、Web サイトを実行してそれが機能することを確認する方法を紹介します。

**メモ:** Express アプリケーションジェネレータは、Express アプリケーション用の唯一のジェネレータというわけではありません。また、生成されたプロジェクトはファイルやディレクトリーを構造化する唯一実行可能な方法というわけではありません。しかしながら、生成されたサイトは、拡張と理解が容易なモジュール構造を持っています。最小限の Express アプリケーションについては、Hello world の例 (Express ドキュメント) を参照してください。

アプリケーションジェネレータを使用する
-------------------

Node 開発環境の設定の一部として、ジェネレータをすでにインストールしているはずです。念のため、NPM パッケージマネージャを使用して、サイト全体にジェネレータツールをインストールします。

```bash
npm install express-generator -g
```

ジェネレータにはいくつかのオプションがあり、それらは `--help` (または `-h`) コマンドを使用してコマンドラインで表示できます。

```bash
> express --help

  Usage: express [options] [dir]

  Options:

    -h, --help           output usage information
        --version        output the version number
    -e, --ejs            add ejs engine support
        --pug            add pug engine support
        --hbs            add handlebars engine support
    -H, --hogan          add hogan.js engine support
    -v, --view <engine>  add view <engine> support (ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)
    -c, --css <engine>   add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)
        --git            add .gitignore
    -f, --force          force on non-empty directory
```

Jade ビューエンジンとプレーン CSS を使用して、`express` を指定するだけで現在のディレクトリー内にプロジェクトを作成できます (ディレクトリー名を指定すると、プロジェクトはその名前のサブフォルダに作成されます)。

```bash
express
```

`--view` を使用してビュー (テンプレート) エンジンを選択したり、`--css` を使用して CSS 生成エンジンを選択したりすることもできます。

**メモ:** テンプレートエンジンを選択するためのその他のオプション (`--hogan`、`--ejs`、`--hbs` など) は推奨されません。`--view` (または `-v`)を使用してください。

### どのビューエンジンを使うべきですか？

Express Application Generator を使用すると、EJS、Hbs、Pug (Jade)、Twig、Vash など、一般的なビュー/テンプレートエンジンを多数設定できます。ただし、ビューオプションを指定しない場合はデフォルトで Jade が選択されます。 Express 自体は、一般的な他のテンプレート言語の多くをサポートすることができます。

**メモ:** ジェネレータでサポートされていないテンプレートエンジンを使用したい場合は、Express でテンプレートエンジンを使用する (Express ドキュメント) およびターゲットビューエンジンのドキュメントを参照してください。

一般的に、あなたが必要とするすべての機能を提供し、あなたがより早く生産的になることを可能にするテンプレートエンジンを選ぶべきです ー もしくは言い換えれば、同じ方法で、他のコンポーネントを選択するということです。テンプレートエンジンを比較する際に考慮すべき点がいくつかあります。

* 生産的になるための時間 - あなたのチームがすでにテンプレート言語の経験があるのなら l その言語を使うことでより速く生産的になるでしょう。そうでない場合は、候補のテンプレートエンジンの相対的な学習曲線を検討する必要があります
* 人気度とアクティビティ - エンジンの人気度と、活発なコミュニティがあるかどうかを確認します。あなたがウェブサイトの生涯にわたって問題を抱えているときにエンジンのサポートを受けることができることが重要です
* スタイル － テンプレートエンジンの中には、"通常の" HTML 内に挿入されたコンテンツを示すために特定のマークアップを使用するものもあれば、別の構文を使用して HTML を構成するものもあります (たとえば、インデントとブロック名を使用)
* パフォーマンス/レンダリング時間
* 機能 - あなたが見ているエンジンが利用可能な以下の機能を持っているかどうかを考慮する必要があります。
    + レイアウトの継承：ベーステンプレートを定義してから、特定のページに対して異なる部分だけを "継承" することができます。これは通常、必要なコンポーネントを多数含めるか、毎回テンプレートを最初から作成することによってテンプレートを作成するよりも優れた方法です
    + "Include" のサポート：他のテンプレートを含めることでテンプレートを構築することを可能にします
    + 簡潔な変数およびループ制御構文
    + テンプレートレベルで変数値をフィルタリングする機能 (例えば、変数を大文字にする、または日付値をフォーマットする)
    + HTML 以外の出力フォーマット (JSON や XML など) を生成する機能
    + 非同期操作とストリーミングのサポート
    + サーバだけでなくクライアントでも使用できます。テンプレートエンジンをクライアント上で使用できる場合、これによりデータを提供し、レンダリングの全部または大部分をクライアント側で行うことができます

**メモ:** **Tip:** インターネット上には、さまざまなオプションを比較するのに役立つ多くのリソースがあります。

このプロジェクトでは、Pug テンプレートエンジン (これは最近名前が変更された Jade エンジンです) を使用します。これは最も一般的な Express/JavaScript テンプレート言語の 1 つで、ジェネレータによってそのままサポートされているためです。

### どの CSS スタイルシートエンジンを使うべきですか？

Express Application Generator を使用すると、最も一般的な CSS スタイルシートエンジン (LESS、SASS、Compass、Stylus) を使用するように構成されたプロジェクトを作成できます。

**メモ:** CSS にはいくつかの制限があり、特定のタスクを困難にします。CSS スタイルシートエンジンを使用すると、CSS を定義するためのより強力な構文を使用してから、ブラウザーで使用するためにその定義を通常の CSS にコンパイルできます。

テンプレートエンジンと同様に、チームを最も生産的にすることができるスタイルシートエンジンを使用する必要があります。このプロジェクトでは、CSS 要件が他のものを使用することを正当化するのに十分に複雑ではないため、通常の CSS (デフォルト) を使用します。

### どのデータベースを使うべきですか？

生成されたコードはデータベースを一切使用しません。 Express アプリケーションは、Node によってサポートされている任意のデータベースメカニズムを使用できます (Express 自体はデータベース管理のための特定の追加の動作や要件を定義していません)。

データベースと統合する方法については、後の記事で説明します。

プロジェクトを作成する
-----------

これから作成するサンプルのローカルライブラリアプリでは、Pug テンプレートライブラリを使用し、CSS スタイルシートエンジンを使用しないで、express-locallibrary-tutorial という名前のプロジェクトを作成します。

まず、プロジェクトを作成する場所に移動し、次に示すようにコマンドプロンプトで Express Application Generator を実行します。

```bash
express express-locallibrary-tutorial --view=pug
```

ジェネレータはプロジェクトのファイルを作成 (そして一覧表示) します。

```bash
   create : express-locallibrary-tutorial
   create : express-locallibrary-tutorial/package.json
   create : express-locallibrary-tutorial/app.js
   create : express-locallibrary-tutorial/public/images
   create : express-locallibrary-tutorial/public
   create : express-locallibrary-tutorial/public/stylesheets
   create : express-locallibrary-tutorial/public/stylesheets/style.css
   create : express-locallibrary-tutorial/public/javascripts
   create : express-locallibrary-tutorial/routes
   create : express-locallibrary-tutorial/routes/index.js
   create : express-locallibrary-tutorial/routes/users.js
   create : express-locallibrary-tutorial/views
   create : express-locallibrary-tutorial/views/index.pug
   create : express-locallibrary-tutorial/views/layout.pug
   create : express-locallibrary-tutorial/views/error.pug
   create : express-locallibrary-tutorial/bin
   create : express-locallibrary-tutorial/bin/www

   install dependencies:
     > cd express-locallibrary-tutorial && npm install

   run the app:
     > SET DEBUG=express-locallibrary-tutorial:* & npm start
```

出力の最後に、ジェネレータは依存関係をどのようにインストールするか (**package.json** ファイルにリストされているとおり)、次にアプリケーションを実行する方法についての指示を提供します (上記の手順は Windows 用です。Linux/ macOS では若干異なります)。

スケルトン Web サイトを実行する
------------------

これで、完全なスケルトンプロジェクトが完成しました。 ウェブサイトは実際にはそれほど多くは行っていませんが、それがどのように機能するかを示すために実行する価値があります。

1. まず、依存関係をインストールします (`install` コマンドはプロジェクトの **package.json** ファイルにリストされているすべての依存関係パッケージを取得します)

```bash
cd express-locallibrary-tutorial
npm install
```

2. その後、アプリケーションを実行します
    * Windows では、次のコマンドを使用します
     bash
    ```bash
    SET DEBUG=express-locallibrary-tutorial:* & npm start

    ```
    * macOS または Linux では、次のコマンドを使用します
     bash
    ```bash
    DEBUG=express-locallibrary-tutorial:* npm start

    ```
3. その後、ブラウザーに http://localhost:3000/ をロードしてアプリにアクセスします

次のようなブラウザーページが表示されるはずです。

![Browser for default Express app generator website](/ja/docs/Learn/Server-side/Express_Nodejs/skeleton_website/ExpressGeneratorSkeletonWebsite.png)

自分自身で *localhost:3000* に提供している、動作する Express アプリケーションがあります。

**メモ:** `npm start` コマンドを使用してアプリを起動することもできます。示されているように DEBUG 変数を指定すると、コンソールロギング/デバッグが有効になります。たとえば、上記のページにアクセスすると、次のようなデバッグ出力が表示されます。

```bash
>SET DEBUG=express-locallibrary-tutorial:* & npm start

> express-locallibrary-tutorial@0.0.0 start D:\express-locallibrary-tutorial
> node ./bin/www

  express-locallibrary-tutorial:server Listening on port 3000 +0ms
GET / 200 288.474 ms - 170
GET /stylesheets/style.css 200 5.799 ms - 111
GET /favicon.ico 404 34.134 ms - 1335
```

ファイルの変更時にサーバの再起動を有効にする
----------------------

Express Web サイトに加えた変更は、現在のサーバを再起動するまで表示されません。変更を加えるたびにサーバを停止して再起動する必要があることはすぐに非常に苛立たしいものになるため、必要に応じてサーバの再起動を自動化することに時間をかける価値があります。

この目的のための最も簡単なツールの 1 つが nodemon です。 これは通常 "ツール" としてグローバルにインストールされますが、ここでは開発者の依存関係としてローカルにインストールして使用するので、プロジェクトを操作する開発者はアプリケーションをインストールするときに自動的に取得されます。スケルトンプロジェクトのルートディレクトリーで次のコマンドを使用します。

```bash
npm install --save-dev nodemon
```

プロジェクトの **package.json** ファイルだけでなく、自分のマシンにグローバルに nodemon をインストールする場合は、次のようにします。

```bash
npm install -g nodemon
```

プロジェクトの **package.json** ファイルを開くと、この依存関係を持つ新しいセクションが表示されます。

```json
  "devDependencies": {
    "nodemon": "^1.14.11"
  }
```

このツールはグローバルにはインストールされていないので (パスに追加しない限り) コマンドラインから起動することはできませんが、NPM はインストールされているパッケージをすべて知っているので、NPM スクリプトから呼び出すことができます。package.json の `scripts` セクションを見つけます。最初は `"start"` で始まる 1 行が含まれています。その行の末尾にカンマを入れて、以下に見られる `"devstart"` 行を追加することによってそれを更新します。

```json
  "scripts": {
    "start": "node ./bin/www",
    "devstart": "nodemon ./bin/www"
  },
```

`devstart` コマンドを指定して、以前とほぼ同じ方法でサーバーを起動することができます。

* Windows では、次のコマンドを使用してください

```bash
SET DEBUG=express-locallibrary-tutorial:* & npm run devstart
```

* macOS または Linux では、次のコマンドを使用してください

```bash
DEBUG=express-locallibrary-tutorial:* npm run devstart
```

**メモ:** プロジェクト内のファイルを編集した場合は、サーバが再起動します (またはコマンドプロンプトで `rs` と入力していつでも再起動できます)。あなたはまだページを更新するためにブラウザーを再読み込みする必要があるでしょう。

"start" は実際には名前付きスクリプトにマップされた NPM コマンドなので、ここでは単に `npm start` ではなく "`npm run <scriptname>`" を呼び出す必要があります。起動スクリプトのコマンドを置き換えることもできますが、開発中は nodemon を使用するだけなので、新しいスクリプトコマンドを作成するのが理にかなっています。

生成されたプロジェクト
-----------

今作成したプロジェクトを見てみましょう。

### ディレクトリー構造

生成されたプロジェクトは、依存関係をインストールしたので、次のようなファイル構造になります (ファイルは "/" が前に付いて**いない**項目です)。**package.json** ファイルは、アプリケーションの依存関係とその他の情報を定義します。また、アプリケーションのエントリポイントである JavaScript ファイル **/bin/www** を呼び出す起動スクリプトも定義されています。これにより、アプリケーションのエラー処理がいくつか設定され、その後 **app.js** が読み込まれて残りの作業が行われます。 アプリのルートは **routes/** ディレクトリーの下の別々のモジュールに格納されています。 テンプレートは /**views** ディレクトリーの下に格納されています。
```

/express-locallibrary-tutorial
    app.js
    /bin
        www
    package.json
    /node_modules
        [about 4,500 subdirectories and files]
    /public
        /images
        /javascripts
        /stylesheets
            style.css
    /routes
        index.js
        users.js
    /views
        error.pug
        index.pug
        layout.pug
```

次のセクションでは、ファイルについてもう少し詳しく説明します。

### package.json

**package.json** ファイルは、アプリケーションの依存関係とその他の情報を定義します。

```json
{
  "name": "express-locallibrary-tutorial",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www",
    "devstart": "nodemon ./bin/www"
  },
  "dependencies": {
    "cookie-parser": "~1.4.3",
    "debug": "~2.6.9",
    "express": "~4.16.2",
    "morgan": "~1.9.0",
    "pug": "~2.0.0-rc.4",
    "serve-favicon": "~2.4.5"
  },
  "devDependencies": {
    "nodemon": "^1.14.11"
  }
}
```

依存関係には、express パッケージと選択したビューエンジン (pug) 用のパッケージが含まれます。さらに、多くの Web アプリケーションで役立つ次のパッケージがあります。

* cookie-parser: Cookie ヘッダーを解析し、`req.cookies` を生成するために使用されます (基本的に Cookie 情報にアクセスするための便利な方法を提供します)
* debug: 小さなノードデバッグユーティリティは、Node コアのデバッグ技術をモデルにしています
* morgan: Node 用の HTTP リクエストロガーミドルウェア
* serve-favicon: ファビコンを提供するためのノードミドルウェア (これはブラウザータブ内のサイト、ブックマークなどを表すために使用されるアイコンです)

scripts セクションは "start" スクリプトを定義します。これは、`npm start` を呼び出してサーバを起動するときに呼び出すスクリプトです。スクリプトの定義から、これは実際に JavaScript ファイル **./bin/www** with node を開始することがわかります。また、"devstart" スクリプトも定義しています。これは、代わりに `npm run devstart` を呼び出すときに呼び出されます。これは同じ **./bin/www** ファイルを開始しますが、node ではなく nodemon を使用します。

```json
  "scripts": {
    "start": "node ./bin/www",
    "devstart": "nodemon ./bin/www"
  },
```

### www ファイル

ファイル **/bin/www** がアプリケーションのエントリポイントです。 これが最初に行うことは、`express()` アプリケーションオブジェクトを設定して返す "本物の" アプリケーションエントリポイント (プロジェクトルート内の **app.js**) である`require()` です。

```js
#!/usr/bin/env node

/\*\*
 \* Module dependencies.
 \*/

var app = require("../app");
```

**メモ:** `require()` は、現在のファイルにモジュールをインポートするために使われるグローバル Node 関数です。 ここでは相対パスを使用し、オプションの (.**js**) ファイル拡張子を省略して **app.js** モジュールを指定します。

このファイルのコードの残りの部分では、特定のポート (環境変数で定義されているか、変数が定義されていない場合は 3000 で定義されている) に設定された `app` を使用して Node HTTP サーバをセットアップします。 今のところ、コードについて他に何も知る必要はありません (このファイル内のすべてが "定型句" です) が、興味があればお気軽にレビューしてください。

### app.js

このファイルは、`express` アプリケーションオブジェクト (慣例では `app` という名前) を作成し、さまざまな設定とミドルウェアを使用してアプリケーションを設定してから、モジュールからアプリケーションをエクスポートします。以下のコードは、アプリオブジェクトを作成およびエクスポートするファイルの一部だけを示しています。

```js
var express = require('express');
var app = express();
...
module.exports = app;
```

上記の **www** エントリポイントファイルに戻ると、このファイルがインポートされたときに呼び出し元に渡されるのは、この `module.exports` オブジェクトです。

**app.js** ファイルを詳しく見ていきましょう。まず、NPM を使用してアプリケーション用に以前にダウンロードした express、serve-favicon、morgan、cookie-parser など、`require()` を使用していくつかの便利な Node ライブラリをファイルにインポートします。path は、ファイルとディレクトリーのパスを解析するためのコア Node ライブラリです。

```js
var express = require("express");
var path = require("path");
var favicon = require("serve-favicon");
var logger = require("morgan");
var cookieParser = require("cookie-parser");
```

それから routes ディレクトリーから `require()` モジュールを呼び出します。これらのモジュール/ファイルには、関連する "ルート" (URL パス) の特定のセットを処理するためのコードが含まれています。たとえばライブラリ内のすべての本をリストするためにスケルトンアプリケーションを拡張するときは、本関連のルートを処理するための新しいファイルを追加します。

```js
var indexRouter = require("./routes/index");
var usersRouter = require("./routes/users");
```

**メモ:** この時点で、モジュールをインポートしたばかりです。 実際にはまだそのルートを使用していません (これはファイルの少し下まで行われます)。

次に、インポートした Express モジュールを使ってアプリオブジェクトを作成し、それを使ってビュー (テンプレート) エンジンを設定します。エンジンの設定には 2 つの部分があります。まず、 '`views`' の値を設定して、テンプレートが保存されるフォルダを指定します (この場合はサブフォルダの **/views**)。それから '`view engine`' の値を設定してテンプレートライブラリ (この場合は "pug") を指定します。

```js
var app = express();

// view engine setup
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "pug");
```

次の一連の関数は `app.use()` を呼び出してミドルウェアライブラリをリクエスト処理チェーンに追加します。以前インポートしたサードパーティのライブラリに加えて、Express がプロジェクトルートの **/public** ディレクトリーにあるすべての静的ファイルを処理するようにするために、`express.static` ミドルウェアを使用します。

```js
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(\_\_dirname, 'public', 'favicon.ico')));
app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, "public")));
```

他のすべてのミドルウェアがセットアップされたので、(以前にインポートした) ルート処理コードをリクエスト処理チェーンに追加します。 インポートされたコードは、サイトのさまざまな部分に特定のルートを定義します。

```js
app.use("/", indexRouter);
app.use("/users", usersRouter);
```

**メモ:** 上記で指定されたパス ('/' と '`/users'`) は、インポートされたファイルで定義されているルートの接頭辞として扱われます。たとえば、インポートされたユーザーモジュールが `/profile` のルートを定義している場合は、`/users/profile` でそのルートにアクセスします。 ルートの詳細については後の記事で説明します。

ファイルの最後のミドルウェアは、エラーと HTTP 404 レスポンス用のハンドラメソッドを追加します。

```js
// catch 404 and forward to error handler
app.use(function (req, res, next) {
  var err = new Error("Not Found");
  err.status = 404;
  next(err);
});

// error handler
app.use(function (err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get("env") === "development" ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render("error");
});
```

Express アプリケーションオブジェクト (app) が完全に設定されました。最後のステップはそれをモジュールのエクスポートに追加することです (これは **/bin/www** によってインポートされることを可能にするものです)。

```js
module.exports = app;
```

### ルート

ルートファイル **/routes/users.js** を以下に示します (ルートファイルは同様の構造を共有しているので、**index.js** も表示する必要はありません)。まず、express モジュールをロードし、それを使って `express.Router` オブジェクトを取得します。それからそのオブジェクトのルートを指定し、最後にモジュールからルーターをエクスポートします (これがファイルが **app.js** にインポートされることを可能にするものです)。

```js
var express = require("express");
var router = express.Router();

/\* GET users listing. \*/
router.get("/", function (req, res, next) {
  res.send("respond with a resource");
});

module.exports = router;
```

このルートは、正しいパターンの HTTP `GET` リクエストが検出されたときに必ず呼び出されるコールバックを定義します。一致パターンは、モジュールのインポート時に指定された経路 ('`/users`') と、このファイルで定義されているもの ('`/`') です。 つまり、このルートは `/users/` の URL が受信されたときに使用されます。

**メモ:** **Tip:** これを試すには、node を使用してサーバを実行し、ブラウザーの URL (http://localhost:3000/users/) にアクセスしてください。「リソースで応答してください」というメッセージが表示されます。

上記の関心事の 1 つは、コールバック関数が 3 番目の引数 '`next`' を持ち、したがって単純なルートコールバックではなくミドルウェア関数であることです。このコードでは現在 `next` 引数を使用していませんが、`'/'` ルートパスに複数のルートハンドラを追加したい場合、将来的には役に立つかもしれません。

### ビュー (テンプレート)

ビュー (テンプレート) は **/views** ディレクトリー (**app.js** で指定されている) に保存され、ファイル拡張子 **.pug** が与えられます。`Response.render()` メソッドは、オブジェクトに渡された名前付き変数の値とともに指定されたテンプレートをレンダリングし、その結果をレスポンスとして送信するために使用されます。以下の **/routes/index.js** のコードでは、テンプレート変数 "title" を渡した "index" テンプレートを使用して、そのルートがどのようにレスポンスをレンダリングするかを確認できます。

```js
/\* GET home page. \*/
router.get("/", function (req, res) {
  res.render("index", { title: "Express" });
});
```

上記のルートに対応するテンプレートを以下に示します(**index.pug**)。構文については後で詳しく説明します。今のところ知る必要があるのは、(変数 `'Express'` を持つ) `title`変数がテンプレートの指定された場所に挿入されることだけです。
```

extends layout

block content
  h1= title
  p Welcome to #{title}
```

自分自身で挑戦
-------

**/routes/users.js** に新しいルートを作成し、URL `/users/cool/` に "You're so cool" というテキストを表示します。 サーバーを実行し、ブラウザーで http://localhost:3000/users/cool/ にアクセスしてテストしてください。

まとめ
---

これで、ローカルライブラリ用のスケルトン Web サイトプロジェクトを作成し、それが Node を使用して実行されることを確認しました。最も重要なのは、プロジェクトの構造も理解しているので、ローカルライブラリのルートとビューを追加するために変更を加える必要がある場所をよく理解していることです。

次に、図書館の Web サイトとして機能するようにスケルトンを変更します。

あわせて参照
------

* Express application generator (Express ドキュメント)
* Using template engines with Express (Express ドキュメント)
* 前のページ
* Overview: Express Nodejs
* 次のページ


Express/Node の紹介 - ウェブ開発を学ぶ

Express/Node の紹介
================

* Overview: Express Nodejs
* 次のページ

Express の最初の記事では「Node って何だろう？」、「Express って何だろう？」という疑問に答え、なぜ Express ウェブフレームワークが特別なのかについて概要を説明します。主な特徴、Express アプリケーションの主な基本要素を大まかに説明します（テスト開発環境についてはここではまだ触れません）。

|  |  |
| --- | --- |
| 前提条件: | 基本的なコンピューターリテラシー。サーバーサイドのウェブサイトプログラミングの一般的な理解、特にウェブサイトにおけるクライアントとサーバーのやりとりの仕組み。 |
| 目標: | Express とは何か、Node とどのような関係があるのか、Express が提供する機能は何か、Express アプリケーションの主な構成要素は何か、について慣れること。 |

Node の紹介
--------

Node（正式には *Node.js*）はオープンソースのクロスプラットフォーム、実行環境で、開発者はあらゆるサーバーサイドのツールやアプリケーションを JavaScript で作成することができます。この実行環境はブラウザーコンテキスト外での使用 (すなわち、コンピューターまたはサーバー OS 上での直接実行) を目的としています。そのため、クライアントサイドではブラウザー固有の JavaScript API が省略され、HTTP やファイルシステムライブラリーを含む従来の OS API がサポートされます。

ウェブサーバー開発の観点から Node には多くの利点があります。

* 素晴らしいパフォーマンス！ Node はウェブアプリケーションのスループットとスケーラビリティを最適化するように設計されており、多くの一般的なウェブ開発の問題 (リアルタイムウェブアプリケーションなど) に非常に適しています
* コードは "plain old JavaScript" で書かれています。つまり、ブラウザーとウェブサーバーの両方のコードを記述しているときに、言語間の "コンテキストシフト" に費やす時間が短くなります
* JavaScript は比較的新しいプログラミング言語であり、他の従来の ウェブサーバー言語（Python、PHP など）と比較して言語設計の改善のメリットがあります。CoffeeScript、ClojureScript、Scala、LiveScript などを使用できるように、新しく普及している多くの言語が JavaScript にコンパイル/変換されます。
* Node パッケージマネージャー (npm) は、何十万もの再利用可能なパッケージへのアクセスを提供します。クラス最高の依存関係解決機能もあり、ほとんどのビルドツールチェーンの自動化にも使用できます。
* Node.js は移植可能です。Microsoft Windows、macOS、Linux、Solaris、FreeBSD、OpenBSD、WebOS、および NonStop OS で利用できます。さらに、多くの ウェブホスティングプロバイダーが、Node サイトをホスティングするための特定のインフラストラクチャとドキュメントが提供しています。
* 非常に活発な第三者のエコシステムと開発者コミュニティがあり、多くの方々が 快く協力しています。

Node HTTP パッケージを使用することで、Node.js で簡単な ウェブサーバーを作成できます。

### Hello Node.js

次の例では、URL `http://127.0.0.1:8000/` にあるあらゆる種類の HTTP リクエストを待ち受ける ウェブサーバーを作成します。リクエストが受信されると、スクリプトは "Hello World" という文字列でレスポンスします。すでに Node をインストールしている場合は、次の手順に従ってこの例を試すことができます。

1. 端末を開きます (Windows ではコマンドラインユーティリティを開きます)。
2. プログラムを保存するフォルダー (たとえば "test-node") を作成し、端末に次のコマンドを入力して移動します。

```bash
cd test-node
```

3. 好きなテキストエディターを使って `hello.js` というファイルを作成し、次のコードを貼り付けます。

```js
// HTTP モジュールの読み込み
const http = require("http");

const hostname = "127.0.0.1";
const port = 8000;

// HTTP サーバーを作成
const server = http.createServer(function (req, res) {
  // HTTP ステータスとコンテンツタイプを持つ HTTP ヘッダーのレスポンスを設定
  res.writeHead(200, { "Content-Type": "text/plain" });

  // レスポンス本体の "Hello World" を送信
  res.end("Hello World\n");
});

// サーバーにアクセスするための URL を出力
server.listen(port, hostname, function () {
  console.log(`Server running at http://${hostname}:${port}/`);
});
```

4. 上記で作成したフォルダーにファイルを保存します。
5. 端末に戻り、次のコマンドを入力します。

```bash
node hello.js
```

最後に、ウェブブラウザーで `http://localhost:8000` に移動します。テキスト以外は空の ウェブページの左上に "**Hello World**" というテキストが表示されます。

ウェブフレームワーク
----------

その他の一般的なウェブ開発タスクは、Node 自体では直接サポートされていません。様々な HTTP の述語 (`GET`, `POST`, `DELETE` など) に特定の処理を追加したい場合、別々の URL パス ("routes") でリクエストを個別に処理したり、静的ファイルを提供したり、テンプレートを使用してレスポンスを動的に作成したり、自分でコードを書いたりする必要があります。そうしない場合はウェブフレームワークを使用して、車輪の再発明を避けることができます。

Express の紹介
-----------

Express は最も一般的な Node ウェブフレームワークであり、他の多くの一般的な Node ウェブフレームワークの基礎となるライブラリーです。これは以下のメカニズムを提供します。

* 異なる URL のパス (ルート) で異なる HTTP 述語を使用してリクエストのハンドラーを作成します。
* テンプレートにデータを挿入してレスポンスを生成するために、「ビュー」レンダリングエンジンと統合します。
* 接続に使用するポートやレスポンスのレンダリングに使用されるテンプレートの場所などの一般的なウェブアプリケーション設定値を設定します。
* リクエスト処理パイプライン内の任意の時点で、追加のリクエスト処理「ミドルウェア」を追加します。

Express 自体はかなりシンプルですが、開発者はほぼすべてのウェブ開発問題に対応する互換性のあるミドルウェアパッケージを作成しています。Cookie、セッション、ユーザーログイン、URL 引数、POST データ、セキュリティヘッダーなどを扱うライブラリーがあります。Express チームが管理するミドルウェアパッケージのリストは、Express Middleware (一般的なサードパーティパッケージのリストとともに) にあります。

**メモ:** この柔軟性は両刃の剣です。ほぼすべての問題や要件に対応するミドルウェアパッケージがありますが、適切なパッケージを使用して作業することは時には挑戦になることがあります。アプリケーションを構造化する「正しい方法」もなく、インターネット上で見つかる多くの例は最適ではないし、ウェブアプリケーションを開発するために必要なことのほんの一部を示しているだけです。

Node と Express はどこから来たのですか？
---------------------------

Node は 2009 年に Linux 用に最初にリリースされました。npm パッケージマネージャは 2010 年にリリースされ、ネイティブ Windows サポートは 2012 年に追加されました。もっと知りたいのであれば、Wikipedia を掘り下げてみてください。

Express は 2010 年 11 月に最初にリリースされ、現在 API のメジャーバージョンが 4 になっています。現在のリリースの変更点については更新履歴を、詳細な履歴リリースノートについては GitHub を参照してください。

Node と Express はどれくらい普及していますか？
------------------------------

ウェブフレームワークの普及は、それが維持されるかどうかの指標であり、ドキュメンテーション、アドオンライブラリー、テクニカルサポートの面でどのようなリソースが利用される可能性が高いかという点で重要です。

サーバー側のフレームワークの普及率は、すぐに利用可能で決定的なものではありません（ただし、各プラットフォームの GitHub プロジェクトや StackOverflow の質問数をカウントするような仕組みを使って、人気を推定することはできます）。より良い質問は、人気のないプラットフォームの問題を避けるために Node と Express が「人気がある」かどうかです。それらは進化し続けていますか？あなたがそれを必要としたら助けを得ることができますか？あなたが Express を学ぶならば、あなたは職を得る機会がありますか？

Express を使用している有名企業の数、コードベースに貢献している人の数、および無料と有料の両方でサポートを提供している人の数に基づけば、Express は一般的なフレームワークです。

Express は指図をしたがりますか？
--------------------

ウェブフレームワークはしばしば自身を「指図をしたがる」または「指図をしない」ものと称します。

指図をしたがるフレームワークは、特定のタスクを扱うのに「正しい方法」があるという考えを持っています。何であれ正しい方法であれば普通よく理解され細かく文書化されているため、（特定のタイプの問題を解決するような）特定の領域における素早い開発をサポートします。しかしながら、彼らが主眼とする領域の外にある問題を解決するにあたっては柔軟性に劣り、利用できるコンポーネントやアプローチの選択肢が限られたものになりがちです。

 一方、指図をしないフレームワークは、目的の達成のためにコンポーネントをつなぎ合わせる最善の方法や、どのコンポーネントを使うかにさえも、あまり制約を設けません。
 開発者は、コンポーネントを自分自身で探す必要があるという手間をかければ、特定のタスクを完了させるのに最適なツールの利用をより容易にします。

Express は指図をしません。リクエストを処理するチェインの中で、互換性のある好きなミドルウェアを、好きな順番で挿し込むことができます。1 つのファイルまたは複数のファイル、任意のディレクトリー構造を使ってアプリケーションを構成できます。ときに選択肢が多すぎるようにも感じられるでしょう。

Express コードはどのように見えますか？
-----------------------

従来のデータ駆動型ウェブサイトでは、ウェブアプリケーションはウェブブラウザー (または他のクライアント) からの HTTP リクエストを待機します。リクエストが受信されると、アプリケーションは URL パターンと、`POST` データまたは `GET` データに含まれる可能性のある関連情報に基づいて、必要なアクションを実行します。必要に応じて、データベースから情報を読み書きしたり、リクエストを満たすために必要な他のタスクを実行することができます。アプリケーションはウェブブラウザーにレスポンスを返し、検索されたデータを HTML テンプレートのプレースホルダに挿入することによってブラウザーが表示する HTML ページを動的に作成することがよくあります。

Express は特定の HTTP 述語 (`GET`, `POST`, `SET` など) と URL パターン ("Route") に対してどの関数が呼び出されるかを指定するメソッドと、どのテンプレート ("view") エンジンが使用されるかを指定するメソッドを提供します。テンプレートエンジンを使用するには、レスポンスをレンダリングするためのテンプレートファイルを配置します。Express ミドルウェアを使用して、Cookie、セッション、およびユーザー、`POST`/`GET` パラメーターなどのサポートを追加することができます。Node がサポートするデータベース・メカニズムを使用できます (Express はデータベース関連の動作を定義しません)。

次のセクションでは、Express およびノード・コードを使用して作業するときに表示される一般的な事項について説明します。

### Helloworld Express

最初に、標準の Express の Hello World の例を考えてみましょう (これについては、以下の各セクションで説明します)。

**メモ:** **Tip:** Node と Express がすでにインストールされている場合 (または次の記事のようにインストールする場合) は、このコードを **app.js** というテキストファイルに保存し、bash コマンドプロンプトで次のように呼び出して実行できます。

**`node ./app.js`**

```js
const express = require("express");
const app = express();
const port = 3000;

app.get("/", function (req, res) {
  res.send("Hello World!");
});

app.listen(port, function () {
  console.log(`Example app listening on port ${port}!`);
});
```

最初の 2 行は `require()` で express モジュールをインポートして Express アプリケーションを作成します。このオブジェクトは伝統的に `app` と呼ばれ、HTTP リクエストのルーティング、ミドルウェアの設定、HTML ビューのレンダリング、テンプレートエンジンの登録、アプリケーションの動作を制御するアプリケーション設定の変更 (環境モード、ルート定義の大文字と小文字の区別など) のためのメソッドがあります。

コードの中央部分 (`app.get` で始まる 3 行) はルート定義を示しています。`app.get()` メソッドは、サイトルートからの相対パス (`'/'`) を持つ HTTP `GET` リクエストがあるたびに呼び出されるコールバック関数を指定します。コールバック関数はリクエストとレスポンスオブジェクトを引数として取り、レスポンスに対して単に `send()` を呼び出して文字列 "Hello World!" を返します。

最後のブロックは 3000 番ポートでサーバーを起動し、コンソールにログコメントを出力します。 サーバーが稼働している場合は、ブラウザーの `localhost:3000` にアクセスして、レスポンスの例を確認することができます。

### モジュールのインポートと作成

モジュールは Node の `require()` 関数を使って他のコードにインポートできる JavaScript ライブラリー/ファイルです。 Express 自体はモジュールです。Express アプリケーションで使用するミドルウェアおよびデータベースライブラリーも同様です。

以下のコードは、例として Express フレームワークを使用して、モジュールを名前でインポートする方法を示しています。 最初に `require()` 関数を呼び出し、モジュールの名前を文字列 (`'express'`) として指定し、返されたオブジェクトを呼び出して Express アプリケーションを作成します。その後、アプリケーションオブジェクトのプロパティと機能にアクセスできます。

```js
const express = require("express");
const app = express();
```

独自のモジュールを作成して、同じ方法でインポートすることもできます。

**メモ:** あなたは自身のモジュールを作成したいと思うでしょう、これはあなたが自身のコードを管理しやすい部品に分けることを可能にします 。ちなみに、モノリシックな単一ファイルのアプリケーションは理解し維持するのが難しいです。モジュールを使用すると、明示的にエクスポートした変数のみがインポートされるため、モジュールを使用すると名前空間を管理するのにも役立ちます。

オブジェクトをモジュールの外部で利用可能にするには、それらを `exports` オブジェクトの追加プロパティとして公開するだけです。たとえば、以下の **square.js** モジュールは `area()` メソッドと `perimeter()` メソッドをエクスポートしたファイルです。

```js
exports.area = function (width) {
  return width \* width;
};
exports.perimeter = function (width) {
  return 4 \* width;
};
```

`require()` を使ってこのモジュールをインポートし、次に示すようにエクスポートされたメソッドを呼び出すことができます。

```js
const square = require("./square"); // require() にはファイル拡張子を除いたファイル名を引数に指定します。
console.log(`The area of a square with a width of 4 is ${square.area(4)}`);
```

**メモ:** モジュールへの絶対パス (または最初に行ったように名前) を指定することもできます。

一度に 1 つのプロパティを構築するのではなく、1 つの割り当てで完全なオブジェクトをエクスポートする場合は、次のように `module.exports` に割り当てます (これを実行して、エクスポートオブジェクトのルートをコンストラクタまたは他の関数にすることもできます)。

```js
module.exports = {
  area(width) {
    return width \* width;
  },

  perimeter(width) {
    return 4 \* width;
  },
};
```

**メモ:** `exports` を与えられたモジュール内の `module.exports` へのショートカットとして考えることができます。実際、`exports` は、モジュールが評価される前に `module.exports` の値に初期化される単なる変数です。 その値はオブジェクト (この場合は空のオブジェクト) への参照です。これは、`exports` が `module.exports` によって参照されるのと同じオブジェクトへの参照を保持することを意味します。また、エクスポートに別の値を代入することで、`module.exports` にバインドされなくなることも意味します。

モジュールの詳細については、モジュール (Node API のドキュメント) を参照してください。

### 非同期 API の使用

JavaScript コードでは、操作に同期 API よりも非同期 API が頻繁に使用されるため、処理に時間がかかることがあります。 同期 API は、各操作を完了してから次の操作を開始できる API です。 たとえば、次のログ関数は同期的で、テキストをコンソールに順番に印刷します(First、Second)。

```js
console.log("First");
console.log("Second");
```

対照的に、非同期 API は、API が操作を開始してすぐに (操作が完了する前に) 戻るものです。操作が終了すると、API は何かのメカニズムを使用して追加の実行を行います。例えば、次のコードでは最初に `setTimeout()` メソッドが呼び出されてすぐに返されても、操作が数秒間完了しないため、 "Second, First" が出力されます。

```js
setTimeout(function () {
  console.log("First");
}, 3000);
console.log("Second");
```

Node はシングルスレッドのイベント駆動型実行環境であるため、ノンブロッキングの非同期 API を使用することは、ブラウザーよりも Node にとってさらに重要です。シングルスレッドとは、サーバーへのすべてのリクエストが (別々のプロセスに分割されるのではなく) 同じスレッドで実行されることを意味します。このモデルは速度とサーバーリソースの点で非常に効率的です。しかし、完了に時間がかかる同期メソッドを呼び出す関数があると、それらは現在のリクエストだけでなく、他のすべてのリクエストがウェブアプリケーションによって処理されることをブロックします。

非同期 API がアプリケーションに完了したことを通知するにはいくつかの方法があります。最も一般的な方法は、非同期 API を呼び出すときにコールバック関数を登録することです。これは、操作が完了したときにコールバックされます。 これが上記で使用されているアプローチです。

**メモ:** コールバックを使用することは、順番に実行しなければならない一連の従属非同期操作がある場合、かなり「面倒」になる可能性があります。これは、複数レベルのネストされたコールバックをもたらすためです。この問題は一般に「コールバック地獄」として知られています。この問題は、async などのモジュールを使用した優れたコーディング方法（http://callbackhell.com/ を参照）、またはプロミスまたは async/await などのネイティブの JavaScript 機能へのリファクタリングによっても軽減できます。Node はコールバック→プロミスの変換を人間工学的に行うために `utils.promisify` という関数を提供しています。

**メモ:** Node と Express の一般的な規約は、エラー優先コールバックを使うことです。この規約では、コールバック関数の最初の値はエラー値ですが、後続の引数には成功データが含まれます。 なぜこのアプローチがこのブログで役に立つのかについての良い説明があります：Node.js の方法 - エラーファーストコールバックについて (fredkschott.com)。

### ルートハンドラーの作成

上記の Hello World Express の例では、サイトルート (`'/'`) への HTTP `GET` リクエストに対して(callback)ルートハンドラー関数を定義しました。

```js
app.get("/", function (req, res) {
  res.send("Hello World!");
});
```

コールバック関数はリクエストとレスポンスオブジェクトを引数として取ります。 この場合、メソッドは単にレスポンスに対して `send()` を呼び出して、文字列 "Hello World!" を返します。リクエスト/レスポンスサイクルを終了するためのレスポンスメソッドは他にも多数あります。たとえば、JSON レスポンスを送信するために `res.json()` を呼び出し、ファイルを送信するために `res.sendFile()` を呼び出すことができます。

**メモ:** **JavaScript tip:** コールバック関数で好きな引数名を使うことができます。 コールバックが呼び出されると、最初の引数は常にリクエストになり、2 番目の引数は常にレスポンスになります。 コールバックの本体で作業しているオブジェクトを識別できるようにそれらの名前を付けることは意味があります。

Express アプリケーションオブジェクトには、他のすべての HTTP 述語のルートハンドラーを定義するためのメソッドもあります。これらのメソッドはほとんど同じ方法で使用されます。

`checkout()`, `copy()`, **`delete()`**, **`get()`**, `head()`, `lock()`, `merge()`, `mkactivity()`, `mkcol()`, `move()`, `m-search()`, `notify()`, `options()`, `patch()`, **`post()`**, `purge()`, **`put()`**, `report()`, `search()`, `subscribe()`, `trace()`, `unlock()`, `unsubscribe()`.

`app.all()` という特別なルーティングメソッドがあります。これはあらゆる HTTP メソッドに応答して呼び出されます。これはすべてのリクエストメソッドの特定のパスにミドルウェア機能をロードするために使用されます。次の例（Express の資料から）は、使用される HTTP 述語に関係なく、 `/secret` へのリクエストに対して実行されるハンドラーを示しています（http モジュールでサポートされている場合）。

```js
app.all("/secret", function (req, res, next) {
  console.log("Accessing the secret section…");
  next(); // 次のハンドラーに制御を渡します。
});
```

ルートを使用すると、URL 内の特定のパターンの文字を照合し、URL からいくつかの値を抽出し、それらをパラメータとしてルートハンドラーに渡すことができます(パラメータとして渡されるリクエストオブジェクトの属性として)。

多くの場合、サイトの特定の部分のルートハンドラーをまとめて、共通のルートプレフィックスを使用してそれらにアクセスすると便利です (たとえば、Wiki のあるサイトでは、1 つのファイルにすべての Wiki 関連ルートがあり、ルートプレフィックス */wiki/* を使用してアクセスすることがあります)。 Express では、これは `express.Router` オブジェクトを使用して実現されます。たとえば、**wiki.js** という名前のモジュールで Wiki ルートを作成してから、次に示すように `Router` オブジェクトをエクスポートできます。

```js
// wiki.js - Wiki ルートモジュール

const express = require("express");
const router = express.Router();

// ホームページルート
router.get("/", function (req, res) {
  res.send("Wiki home page");
});

// about ページルート
router.get("/about", function (req, res) {
  res.send("About this wiki");
});

module.exports = router;
```

**メモ:** `Router` オブジェクトにルートを追加することは、(前述のように) `app` オブジェクトにルートを追加するのと同じです。

メインアプリケーションファイルでルーターを使用するには、ルートモジュール (**wiki.js**) を `require()` してから、Express アプリケーションで `use()` を呼び出してミドルウェア処理パスにルーターを追加します。 2 つの経路は `/wiki/` と `/wiki/about/` からアクセス可能になります。

```js
const wiki = require("./wiki.js");
// …
app.use("/wiki", wiki);
```

ルートを扱うことについて、そして特に `Router` を使うことについてもっとより多くのことがあります。それらについては、リンクされたセクション、ルートとコントローラ (en-US)で説明します。

### ミドルウェアの使用

ミドルウェアは静的ファイルの提供からエラー処理、HTTP レスポンスの圧縮まで、Express アプリケーションで広く使用されています。ルート関数は HTTP クライアントにレスポンスを返すことで HTTP リクエスト - レスポンスサイクルを終了しますが、ミドルウェア関数は通常、リクエストまたはレスポンスに対して何らかの操作を実行してから、「スタック」内の次の機能を呼び出します。これは、より多くのミドルウェアまたはルートハンドラーの場合があります。ミドルウェアが呼び出される順序はアプリ開発者次第です。

**メモ:** ミドルウェアは任意の操作を実行し、任意のコードを実行し、リクエストおよびレスポンスオブジェクトに変更を加えることができ、またリクエスト - レスポンスサイクルを終了することもできます。サイクルが終了しない場合は、`next()` を呼び出して次のミドルウェア機能に制御を渡す必要があります (そうでない場合、リクエストは中断されたままになります)。

Cookie の操作、セッション、ユーザー認証、リクエスト `POST` および JSON データへのアクセス、ロギングなどの一般的なウェブ開発タスクを簡素化するために、ほとんどのアプリはサードパーティ製ミドルウェアを使用します。Express チームが管理するミドルウェアパッケージのリストを見つけることができます。(他の人気のあるサードパーティのパッケージも含みます)。他の Express パッケージは npm パッケージマネージャーで入手できます。

サードパーティのミドルウェアを使用するには、まず npm を使用してそれをアプリにインストールする必要があります。たとえば、 morgan という HTTP リクエストロガーミドルウェアをインストールするには、次のようにします。

```bash
npm install morgan
```

次に、Express アプリケーションオブジェクトで `use()` を呼び出してミドルウェアをスタックに追加できます。

```js
const express = require("express");
const logger = require("morgan");
const app = express();
app.use(logger("dev"));
// …
```

**メモ:** ミドルウェアおよびルーティング機能は、宣言されている順序で呼び出されます。ミドルウェアによっては、順序が重要です (たとえば、セッションミドルウェアが cookie ミドルウェアに依存している場合は、最初に cookie ハンドラーを追加する必要があります)。ほとんどの場合、ミドルウェアはルートを設定する前に呼び出されます。そうでないとルートハンドラーがミドルウェアによって追加された機能にアクセスすることはできません。

あなたは自身のミドルウェア機能を書くことができ、そうする必要があるでしょう (エラー処理コードを作成するためだけの場合)。ミドルウェア関数とルートハンドラーコールバックの**唯一の**違いは、ミドルウェア関数が次に `next` 引数を持つことです。ミドルウェア関数はリクエストサイクルを完了させるものではない場合に呼び出されます (ミドルウェア関数が呼び出されるとき、その中には呼び出される *next* 関数が含まれていなければなりません)。

ミドルウェア関数は、`app.use()` を使用してすべてのレスポンスに対する処理チェーンに追加することもできますし、関連するメソッド、`app.get()`、`app.post()` などを使って特定の HTTP 動詞に対する処理チェーンにも追加することができます。ルートはどちらの用途でも同じように指定しますが、`app.use()` を呼び出す場合はルートがオプションになります。

以下の例は、ルートの有無に関わらず、両方の方法を使用してミドルウェア関数を追加する方法を示しています。

```js
const express = require("express");
const app = express();

// ミドルウェア関数の例
const a\_middleware\_function = function (req, res, next) {
  // Perform some operations
  next(); // next() を呼ぶことで Express はチェイン中の次のミドルウェア関数を呼びます。

// すべてのルートと述語に対して use() で関数を追加します。
app.use(a_middleware_function);

// 指定ルートに対して use() でミドルウェア関数を追加します。
app.use("/someroute", a_middleware_function);

// 指定の HTTP 述語とルートに対してミドルウェア関数を追加します。
app.get("/", a_middleware_function);

app.listen(3000);
```

**メモ:** 上記ではミドルウェア関数を別々に宣言してからコールバックとして設定しています。以前のルートハンドラー関数では、使用時にコールバック関数を宣言しました。JavaScript では、どちらの方法も有効です。

Express の資料には、Express ミドルウェアの使用および作成に関するより優れた資料があります。

### 静的ファイルの提供

express.static ミドルウェアを使用して、画像、CSS、JavaScript などの静的ファイルを提供できます (`static()` は、実際には Express の**一部**である唯一のミドルウェア関数です)。 たとえば、node を呼び出す場所と同じレベルで、'**public**' という名前のディレクトリーから画像、CSS ファイル、および JavaScript ファイルを配信するには、次の行を使用します。

```js
app.use(express.static("public"));
```

public ディレクトリー内のファイルはすべて、ベース URL にそのファイル名 (ベースの "public" ディレクトリーに対する相対パス) を追加することによって提供されます。そのため、例えば：
```

http://localhost:3000/images/dog.jpg
http://localhost:3000/css/style.css
http://localhost:3000/js/app.js
http://localhost:3000/about.html
```

`static()` を複数回呼び出して、複数のディレクトリーを扱うことができます。ファイルが 1 つのミドルウェア関数で見つからない場合は、そのファイルは後続のミドルウェアに単純に渡されます (ミドルウェアが呼び出される順序は宣言の順序に基づいています)。

```js
app.use(express.static("public"));
app.use(express.static("media"));
```

ファイルをベース URL に追加するのではなく、静的 URL の仮想プレフィックスを作成することもできます。たとえば、ここではファイルがプレフィックス "/media" でロードされるようにマウントパスを指定します。

```js
app.use("/media", express.static("public"));
```

これで、`public` ディレクトリーにあるファイルを `/media` パスプレフィックスから読み込むことができます。
```

http://localhost:3000/media/images/dog.jpg
http://localhost:3000/media/video/cat.mp4
http://localhost:3000/media/cry.mp3
```

詳しくは、Express での静的ファイルの提供を参照してください。

### エラーの処理

エラーは、通常の 3 つの引数ではなく、4 つの引数 `(err、req、res、next)` を持つ 1 つ以上の特別なミドルウェア関数によって処理されます。例えば：

```js
app.use(function (err, req, res, next) {
  console.error(err.stack);
  res.status(500).send("Something broke!");
});
```

これらは必要なコンテンツを返すことができますが、他のすべての `app.use()` および呼び出しをルーティングした後に呼び出して、リクエスト処理プロセスの最後のミドルウェアになるようにする必要があります。

Express にはエラーハンドラーが組み込まれています。これは、アプリで発生する可能性がある残りのエラーを処理します。 このデフォルトのエラー処理ミドルウェア関数は、ミドルウェア関数スタックの最後に追加されます。`next()` にエラーを渡し、それをエラーハンドラーで処理しなかった場合、それは組み込みエラーハンドラーによって処理されます。エラーはスタックトレースとともにクライアントに書き込まれます。

**メモ:** スタックトレースは実稼働環境に含まれていません。プロダクションモードで実行するには、環境変数 `NODE_ENV` を '`production`' に設定する必要があります。

**メモ:** HTTP 404 およびその他の "エラー" ステータスコードはエラーとして扱われません。これらを処理したい場合は、ミドルウェア関数を追加して処理することができます。詳しくは FAQ を見てください。

詳しくはエラー処理（Express ドキュメント） を参照してください。

### データベースの使用

Express アプリケーションは、Node によってサポートされている任意のデータベースメカニズムを使用できます (Express 自体はデータベース管理のための特定の追加の動作や要件を定義していません)。PostgreSQL、MySQL、Redis、SQLite、MongoDB などを含む多くのオプションがあります。

これらを使用するには、まず npm を使用してデータベースドライバをインストールする必要があります。たとえば、一般的な NoSQL MongoDB 用のドライバをインストールするには、次のコマンドを使用します。

```bash
npm install mongodb
```

データベース自体はローカルにインストールすることも、クラウドサーバーにインストールすることもできます。Express コードではドライバが必要で、データベースへの接続から、作成、参照、更新、削除 (CRUD) 操作を実行します。以下の (Express ドキュメントからの) 例は、MongoDB を使ってどのように「哺乳類の」レコードを見つけることができるかを示しています。

これは mongodb バージョン 2.2.33 までの古いバージョンで動作します。

```js
const MongoClient = require("mongodb").MongoClient;

MongoClient.connect("mongodb://localhost:27017/animals", (err, db) => {
  if (err) throw err;

  db.collection("mammals")
    .find()
    .toArray((err, result) => {
      if (err) throw err;

      console.log(result);
    });
});
```

mongodb バージョン 3.0 以上のためのコードは次の通りです。

```js
const MongoClient = require("mongodb").MongoClient;

MongoClient.connect("mongodb://localhost:27017/animals", (err, client) => {
  if (err) throw err;

  const db = client.db("animals");
  db.collection("mammals")
    .find()
    .toArray((err, result) => {
      if (err) throw err;
      console.log(result);
      client.close();
    });
});
```

もう 1 つの一般的な方法は、Object Relational Mapper ( "ORM") を介して間接的にデータベースにアクセスすることです。このアプローチではデータを「オブジェクト」または「モデル」として定義し、ORM はそれらを基礎となるデータベース形式にマッピングします。このアプローチには、開発者としてデータベースのセマンティクスではなく JavaScript オブジェクトの観点から考え続けることができ、受信データの検証とチェックを実行するための明らかな場所があるという利点があります。データベースについての詳細は、後の記事で説明します。

詳しくはデータベース統合（Express ドキュメント） を参照してください。

### データのレンダリング（ビュー）

テンプレートエンジン（Express のドキュメントでは「ビューエンジン」とも呼ばれています）を使用すると、ページの生成時に埋められるデータのプレースホルダを使用して、テンプレート内の出力ドキュメントの構造を指定できます。テンプレートは HTML の作成によく使用されますが、他の種類の文書も作成できます。 Express はいくつかのテンプレートエンジンをサポートしています。ここでは、より人気の高いエンジンの便利な比較ができます。JavaScript テンプレートエンジンの比較：Jade、Moustache、Dust など

次に示すように、アプリケーション設定コードで、使用するテンプレートエンジンと、Express が 'ビュー' および 'ビューエンジン' 設定を使用してテンプレートを探す場所を設定します（テンプレートライブラリーを含むパッケージもインストールする必要があります！）

```js
const express = require("express");
const path = require("path");
const app = express();

// ('views') テンプレートを含むディレクトリーを設定
app.set("views", path.join(__dirname, "views"));

// 利用するビューエンジン、この場合は 'some\_template\_engine\_name' を設定
app.set("view engine", "some\_template\_engine\_name");
```

テンプレートの外観は使用するエンジンによって異なります。"title" および "message" という名前のデータ変数のプレースホルダを含む "index.<テンプレート拡張子>" という名前のテンプレートファイルがあると仮定すると、ルートハンドラー関数で `Response.render()` を呼び出して HTML レスポンスを作成し、送信することになります。

```js
app.get("/", function (req, res) {
  res.render("index", { title: "About dogs", message: "Dogs rock!" });
});
```

詳しくは Express でのテンプレートエンジンの使用（Express ドキュメント） を参照してください。

### ファイル構造

Express は、構造や使用するコンポーネントに関しては何も想定していません。ルート、ビュー、静的ファイル、およびその他のアプリケーション固有のロジックは、任意のディレクトリー構造を持つ任意の数のファイルに存在できます。 Express アプリケーション全体を 1 つのファイルにまとめることは完全に可能ですが、通常は機能 (アカウント管理、ブログ、ディスカッション掲示板など) およびアーキテクチャ上の問題のドメイン (MVC アーキテクチャを使用している場合は、モデル、ビュー、コントローラーなど) に基づいてアプリケーションをファイルに分割します。

後のトピックでは、ウェブアプリケーションを作成するために簡単に拡張できるモジュール式のアプリケーションスケルトンを作成する Express Application Generator を使用します。

まとめ
---

おめでとうございます、Express/Node の旅の最初のステップを完了しました。これで Express と Node の主な利点と、Express アプリケーションの主要部分がどのように見えるか (ルート、ミドルウェア、エラー処理、およびテンプレートコード) をおおまかに理解できています。また、Express は指図しないフレームワークであるため、これらの部分をどのようにまとめるかやどのライブラリーを使用するかは、ほとんどあなた次第です。

もちろん、Express は意図的に非常に軽量なウェブアプリケーションフレームワークであるため、その利点と可能性の多くはサードパーティのライブラリーと機能からもたらされています。以下の記事でそれらをより詳しく見ていきます。次回の記事では、Node 開発環境のセットアップについて見ていきます。そうすれば、いくつかの Express コードが実際に動作しているところを見始めることができます。

関連情報
----

* Venkat.R - Manage Multiple Node versions
* Modules (Node API docs)
* Express（ホームページ）
* 基本的なルーティング（Express ドキュメント）
* ルーティング（Express ドキュメント）
* Express でのテンプレート・エンジンの使用（Express ドキュメント）
* ミドルウェアの使用（Express ドキュメント）
* Express アプリケーションで使用するミドルウェアの作成（Express ドキュメント）
* データベースの統合（Express ドキュメント）
* Express での静的ファイルの提供（Express ドキュメント）
* エラー処理（Express ドキュメント）
* Overview: Express Nodejs
* 次のページ


Express チュートリアル: 地域図書館の Web サイト - ウェブ開発を学ぶ

Express チュートリアル: 地域図書館の Web サイト
===============================

* 前のページ
* Overview: Express Nodejs
* 次のページ

実用的なチュートリアルシリーズの最初の記事では、これから学ぶことについて説明します。そして、私たちがこれから取り組んでいき、その後の記事で進化していく「地域図書館」のサンプルウェブサイトの概要を説明します。

| 前提条件: | Express のイントロダクションを読んでください。以下の記事では、Node 開発環境を設定する必要もあります。 |
| --- | --- |
| 目標: | このチュートリアルで使用されているサンプルアプリケーションを紹介し、どのトピックがカバーされるのかを読者が理解できるようにします。 |

概要
--

MDN "Local Library" Express (Node) チュートリアルへようこそ。このチュートリアルでは、地域図書館の目録を管理するために使用される可能性があるウェブサイトを開発します。

この一連のチュートリアル記事では、次のことを行います。

* Express Application Generator ツールを使用して、スケルトンウェブサイトとアプリケーションを作成します。
* Node ウェブサーバーを起動および停止します。
* データベースを使用してアプリケーションのデータを保存します。
* さまざまな情報を要求するためのルートを作成し、ブラウザーに表示するデータを HTML としてレンダリングするためのテンプレート ("ビュー" )を作成します
* フォームを操作します。
* アプリケーションを運用環境にデプロイします。

あなたはすでにこれらのトピックのいくつかについて学び、他のものについても簡単に触れました。チュートリアルシリーズの最後までに、簡単な Express アプリケーションを自分で開発するのに十分な知識があるはずです。

LocalLibrary ウェブサイト
-------------------

*LocalLibrary* は、この一連のチュートリアルの過程で作成および進化するウェブサイトの名前です。ご想像のとおり、この ウェブサイトの目的は利用できる書籍を閲覧したり自分のアカウントを管理したりできる、地元の小さな図書館用のオンライン目録を提供することです。

この例は慎重に選択されています。必要なだけ詳細を表示することも、ほとんどすべての Express 機能を見せるために使用することもできるためです。さらに重要なことに、それはどんなウェブサイトでも必要とする機能性への*ガイド付きの*道筋を提供することができます：

* 最初のいくつかのチュートリアル記事では、図書館のメンバーがどの本が利用できるかを調べるために使用できる簡単な*ブラウズ専用*ライブラリを定義します。これにより、ほぼすべての ウェブサイトに共通の操作、つまりデータベースからのコンテンツの読み取りと表示を探ることができます。
* 先へ進むにつれて、図書館の例は自然に拡張され、より高度な ウェブサイト機能を実演します。たとえば、新しい本を作成できるようにライブラリを拡張し、これを使用してフォームの使用方法を示し、ユーザ認証をサポートすることができます。

これは非常に拡張可能な例ですが、***Local**Library* と呼ばれる理由があります。私たちは Express をすぐに使い始めるための最小限の情報を示すことを望んでいます。その結果、私たちは本に関する情報、本のコピー、作者、その他の重要な情報を保存します。ただし、図書館が貸し出す可能性のある他のアイテムに関する情報を保存したり、複数の図書館サイトやその他の "大きな図書館" 機能をサポートするために必要なインフラストラクチャを提供することはしません。

私は立ち往生しています、どこでソースを入手できますか？
---------------------------

チュートリアルを進めていくうちに、適切なコードスニペットを各ポイントにコピーして貼り付けることができます。また、他のコードも (ある程度の手引きを付けて) 自身で拡張することを望んでいます。

すべてのコードスニペットをコピーして貼り付けるのではなく、それらを入力してみてください。次回同様のコードを書くときに、コードに慣れ親しんでいることになるので、長期的に役に立ちます。

あなたが立ち往生したならば、Github のここで ウェブサイトの完全に開発されたバージョンを見つけることができます。

**メモ:** この文書でテストされた Node、Express、および他のモジュールの特定のバージョンは、プロジェクト package.json にリストされています。

まとめ
---

*LocalLIbrary* ウェブサイトと、これから学ぶことについて少し知りました。今度は私たちの例を含むスケルトンプロジェクトの作成を開始します。

* 前のページ
* Overview: Express Nodejs
* 次のページ


Express チュートリアル Part 3: データベースの使用 (Mongoose を使用) - ウェブ開発を学ぶ

Express チュートリアル Part 3: データベースの使用 (Mongoose を使用)
================================================

* 前のページ
* Overview: Express Nodejs
* 次のページ  (en-US)

この記事ではデータベースと、それらを Node/Express アプリケーションで使用する方法について簡単に紹介します。続いて、Mongoose を使用して地域図書館 Web サイトへのデータベースアクセスを提供する方法を説明します。 オブジェクトスキーマとモデルの宣言方法、主なフィールドタイプ、および基本的な検証について説明します。また、モデルデータにアクセスするための主な方法についても簡単に説明します。

| 前提条件: | Express チュートリアル Part 2: スケルトン Web サイトの作成 |
| --- | --- |
| 目標: | Mongoose を使用して独自のモデルを設計および作成できるようになる。 |

概要
--

図書館職員は本と借り手についての情報を保存するためにローカルライブラリ Web サイトを使いますが、図書館員は本をブラウズして検索し、利用可能なコピーがあるかどうかを調べ、そしてそれらを予約または借りるために使います。情報を効率的に保存および取得するために、データベースに保存します。

Express アプリケーションはさまざまなデータベースを使用できます。作成、読み取り、更新、削除 (CRUD) 操作を実行するために使用できるいくつかのアプローチがあります。 このチュートリアルではいくつかの利用可能なオプションの簡単な概要を説明し、次に選択された特定のメカニズムを詳細に表示します。

### どのデータベースを使用できますか？

Express アプリは Node でサポートされている任意のデータベースを使用できます (Express 自体はデータベース管理のための特定の追加の動作や要件を定義していません)。 PostgreSQL、MySQL、Redis、SQLite、MongoDB など、多くの一般的なオプションがあります。

データベースを選択するときは、生産性/学習時間の曲線、パフォーマンス、複製/バックアップの容易さ、コスト、コミュニティサポートなどのことを考慮する必要があります。「最高の」データベースは 1 つもありませんが、ほとんどの一般的なソリューションは、ローカルライブラリのような中小規模のサイトでは十分条件を満たしているはずです。

オプションの詳細については、データベース統合 (Express ドキュメント) を参照してください。

### データベースを利用するための最良の方法は何ですか？

データベースにインタラクティブにアプローチするには 2 つの方法があります。

* データベースのネイティブクエリ言語 (例：SQL)を使用する
* オブジェクトデータモデル ("ODM")／オブジェクトリレーショナルモデル ("ORM") を使用する。ODM/ORM は Web サイトのデータを JavaScript オブジェクトとして表し、それが基になるデータベースにマッピングされます。一部の ORM は特定のデータベースに関連付けられていますが、他のデータベースはデータベースに依存しないバックエンドを提供しています

SQL、またはデータベースでサポートされているクエリ言語を使用すると、最高のパフォーマンスが得られます。ODM は、変換コードを使用してオブジェクトとデータベース形式の間のマッピングを行うため、処理が遅くなることが多く、最も効率的なデータベースクエリが使用されない可能性があります (これは、ODM がさまざまなデータベースバックエンドをサポートしている場合に特に当てはまります。サポートされているデータベース機能に関して、さらに妥協する必要があります)。

ORM を使用する利点は、プログラマがデータベースのセマンティクスではなく JavaScript オブジェクトの観点から考え続けることができることです。これは、同じデータベースまたは異なる Web サイトで異なるデータベースを扱う必要がある場合に特に当てはまります。またデータの検証とチェックを実行するための明らかな場所を提供します。

**メモ:** **Tip:** ODM/ORM を使用すると、多くの場合、開発と保守のコストが削減されます。ネイティブのクエリ言語に精通しているかパフォーマンスが最優先であるのでなければ、ODM の使用を積極的に検討するべきです。

### どの ORM/ODM を使うべきですか？

NPM パッケージマネージャのサイトには、多数の ODM/ORM ソリューションがあります (サブセットの odm タグおよび orm タグを調べてください)。

執筆時点で一般的だったいくつかの解決策は、次のとおりです。

* Mongoose: Mongoose は、非同期環境で動作するように設計された MongoDB オブジェクトモデリングツールです
* Waterline: Express ベースの Sails Web フレームワークから抽出された ORM。Redis、MySQL、LDAP、MongoDB、Postgres など、さまざまなデータベースにアクセスするための統一された API を提供します
* Bookshelf: Promise ベースおよび従来の callback インターフェイスの両方を備え、トランザクションのサポート、熱心な/入れ子になったリレーションの読み込み、多態的な関連付け、および 1 対 1、1 対多、および多対多のリレーションのサポートを提供します。PostgreSQL、MySQL、および SQLite3 で動作します
* Objection: SQL とその基盤となるデータベースエンジン (SQLite 3、Postgres、および MySQL をサポート) の全機能を使用することを可能な限り簡単にします
* Sequelize は Node.js と io.js のための Promise ベースの ORM です。PostgreSQL、MySQL、MariaDB、SQLite、および MSSQL のダイアレクトをサポートし、堅実なトランザクションサポート、リレーション、リードレプリケーションなどを備えています
* Node ORM2 は NodeJS のオブジェクトリレーションマネージャです。MySQL、SQLite、Progres をサポートし、オブジェクト指向のアプローチを使用してデータベースを操作するのを助けます
* JugglingDB は NodeJS 用のクロス DB ORM で、最も一般的なデータベースフォーマットにアクセスするための共通インターフェイスを提供します。現在 MySQL、SQLite3、Postgres、MongoDB、Redis および js-memory-storage をサポートしています (テスト用の自己記述エンジンのみ)

原則として、解決策を選択する際には、提供されている機能と "コミュニティ活動" (ダウンロード、コントリビュート、バグレポート、ドキュメントの品質など) の両方を考慮する必要があります。この記事を書いている時点では、Mongoose は最も人気のある ODM であり、データベースに MongoDB を使用している場合は妥当な選択です。

### ローカルライブラリに Mongoose と MongoDB を使用する

ローカルライブラリの例 (およびこのトピックの残りの部分) では、Mongoose ODM を使用してライブラリデータにアクセスします。Mongoose は、ドキュメント指向のデータモデルを使用するオープンソースの NoSQL データベースである MongoDB のフロントエンドとして機能します。MongoDB データベースの "ドキュメント" の "コレクション" は、リレーショナルデータベースの "行" の "テーブル" に似ています。

この ODM とデータベースの組み合わせは、Node コミュニティで非常に人気があります。これは、ドキュメントの保存とクエリのシステムが JSON に非常に似ているため、JavaScript 開発者にはよく知られているためです。

**メモ:** **Tip:** Mongoose を使用するために MongoDB を知っている必要はありませんが、Mongoose のドキュメントの一部は、MongoDB に慣れている方が使いやすく理解しやすいものです。

このチュートリアルの残りの部分では、ローカルライブラリ Web サイトの例の Mongoose スキーマとモデルを定義してアクセスする方法を示します。

ローカルライブラリモデルの設計
---------------

いきなりモデルのコーディングを始める前に、格納する必要があるデータと、さまざまなオブジェクト間の関係について検討することをお勧めします。

書籍に関する情報 (タイトル、概要、著者、ジャンル、ISBN) を保存する必要があること、および複数のコピーが利用可能であること (グローバルに一意の ID、利用状況など) があることを知っています。著者の名前だけではなく、著者に関するより多くの情報を格納する必要があるかもしれません。また、同じ名前または類似の名前を持つ著者が複数いる可能性があります。書籍のタイトル、著者、ジャンル、およびカテゴリに基づいて情報を並べ替えることができるようにします。

モデルを設計するときは、すべての "オブジェクト" (関連情報のグループ) ごとに別々のモデルを用意するのが合理的です。 この場合、明らかなオブジェクトは本、本のインスタンス、および作者です。

Web サイト自体に選択肢をハードコーディングするのではなく、モデルを使用して選択肢の選択肢 (たとえば選択肢のドロップダウンリストなど) を表すこともできます - すべてのオプションが事前にわかっていない場合や変更される可能性がある場合は、これをお勧めします。このタイプのモデルの明らかな候補は本のジャンルです (例：サイエンスフィクション、フランス詩など)。

モデルとフィールドを決めたら、それらの関係について考える必要があります。

そのことを念頭に置いて、以下の UML 関連図は、この場合に定義するモデルを (ボックスとして) 示しています。上記で説明したように、本のモデル (本の一般的な詳細)、本のインスタンス (システムで利用可能な本の特定の物理コピーのステータス)、および作成者のモデルを作成しました。また、値を動的に作成できるように、ジャンルのモデルを用意することにしました。`BookInstance:status` のモデルを使用しないことにしました - 許容値は変更しないと考えられるので、許容値をハードコードします。各ボックス内には、モデル名、フィールド名と型、そしてメソッドとその戻り型が表示されます。

この図には、モデル間の関係 (それらの多重度も含む) も示されています。多重度は、関係内に存在する可能性がある各モデルの番号 (最大および最小) を示す図上の番号です。たとえば、ボックス間の接続線は、`Book` と `Genre` が関連していることを示しています。`Book` モデルに近い数字は、ジャンルに 0 個以上の Book がある必要があることを示しており、線のもう一方の端にある`Genre` の隣の数字は、本に 0 個以上の関連する`Genre`があることを示しています。

**メモ:** 下記の Mongoose 入門書で説明されているように、1 つのモデルだけで documents/models 間の関係を定義するフィールドがあるほうがよいでしょう (他のモデルで関連する `_id` を検索することによって逆の関係を見つけることができます)。以下では、Book スキーマの Book/Genre と Book/Author の関係、および BookInstance スキーマの Book/BookInstance の関係を定義します。この選択は多少恣意的でした - 他のスキーマでも同じようにフィールドを持つことができました。

![Mongoose Library Model with correct cardinality](/ja/docs/Learn/Server-side/Express_Nodejs/mongoose/Library%20Website%20-%20Mongoose_Express.png)

**メモ:** 次のセクションでは、モデルの定義方法と使用方法を説明する基本的な入門書を提供します。お読みになったところで、上の図の各モデルをどのように構築するかを検討してください。

Mongoose 入門書
------------

このセクションでは、Mongoose を MongoDB データベースに接続する方法、スキーマとモデルを定義する方法、そして基本的なクエリを作成する方法の概要を説明します。

**メモ:** この入門書は、npm の Mongoose クイックスタートと公式ドキュメントに "大きく影響を受けています"。

### Mongoose と MongoDB のインストール

Mongoose は他の依存関係と同じようにあなたのプロジェクト (**package.json**) にインストールされます。つまり NPM を使用します。インストールするには、プロジェクトフォルダ内で次のコマンドを使用します。

```bash
npm install mongoose
```

Mongoose をインストールすると、MongoDB データベースドライバを含むすべての依存関係が追加されますが、MongoDB 自体はインストールされません。 MongoDB サーバをインストールする場合は、さまざまな OS 用のインストーラをここからダウンロードしてローカルにインストールできます。クラウドベースの MongoDB インスタンスを使用することもできます。

**メモ:** このチュートリアルでは、mLab クラウドベースの Database as a Service サンドボックス層として使用してデータベースを提供します。これは開発に適しており、オペレーティングシステムの "インストール" に依存しないため (database-as-a-service も本番データベースに使用することができる 1 つのアプローチです)、チュートリアルに適しています。

### MongoDB への接続

Mongoose は MongoDB データベースへの接続を必要とします。以下のように、`require()` して `mongoose.connect()` でローカルにホストされているデータベースに接続することができます。

```js
//Import the mongoose module
var mongoose = require("mongoose");

//Set up default mongoose connection
var mongoDB = "mongodb://127.0.0.1/my\_database";
mongoose.connect(mongoDB);
// Get Mongoose to use the global promise library
mongoose.Promise = global.Promise;
//Get the default connection
var db = mongoose.connection;

//Bind connection to error event (to get notification of connection errors)
db.on("error", console.error.bind(console, "MongoDB connection error:"));
```

デフォルトの `Connection` オブジェクトは `mongoose.connection` で取得できます。接続されると、open イベントが `Connection` インスタンスで発生します。

**メモ:** **Tip:** 追加のコネクションを作成する必要がある場合は、`mongoose.createConnection()` を使用できます。 これは `connect()` と同じ形式のデータベース URI (ホスト、データベース、ポート、オプションなど) を取り、`Connection` オブジェクトを返します。

### モデルの定義と作成

モデルは `Schema` インターフェイスを使用して定義されます。スキーマを使用すると、各ドキュメントに格納されているフィールドとその検証要件およびデフォルト値を定義できます。さらに、データ型や他のフィールドと同じように使用できるが実際にはデータベースに格納されていない仮想プロパティも扱いやすいように、静的メソッドおよびインスタンスヘルパーメソッドを定義できます。(もう少し後で説明します)。

その後、スキーマは `mongoose.model()` メソッドを使用してモデルに "コンパイル" されます。モデルを作成したら、それを使用して特定のタイプのオブジェクトを検索、作成、更新、および削除できます。

**メモ:** 各モデルは MongoDB データベース内のドキュメントのコレクションにマップされます。ドキュメントはモデル `Schema` で定義されたフィールド/スキーマタイプを含みます。

#### スキーマの定義

以下のコードは、単純なスキーマを定義する方法を示しています。最初に mongoose を `require()` し、次に Schema コンストラクタを使用して新しいスキーマインスタンスを作成し、コンストラクタの object パラメータで内部のさまざまなフィールドを定義します。

```js
//Require Mongoose
var mongoose = require("mongoose");

//Define a schema
var Schema = mongoose.Schema;

var SomeModelSchema = new Schema({
  a\_string: String,
  a\_date: Date,
});
```

上記の場合、文字列と日付の 2 つのフィールドしかありません。次のセクションでは、他のフィールドタイプ、検証、その他の方法について説明します。

#### モデルを作成する

モデルは、`mongoose.model()` メソッドを使用してスキーマから作成されます。

```js
// Define schema
var Schema = mongoose.Schema;

var SomeModelSchema = new Schema({
  a\_string: String,
  a\_date: Date,
});

// Compile model from schema
var SomeModel = mongoose.model("SomeModel", SomeModelSchema);
```

最初の引数はあなたのモデル用に作成されるコレクションの単数形の名前です (Mongoose は上記の SomeModel モデル用のデータベースコレクションを作成します)、そして 2 番目の引数はモデルの作成に使用したいスキーマです。

**メモ:** モデルクラスを定義したら、それらを使用してレコードを作成、更新、または削除し、クエリを実行してすべてのレコードまたは特定のレコードのサブセットを取得できます。これを行う方法をモデルの使用セクションで、そしてビューを作成するときに示します。

#### スキーマ型 (フィールド)

スキーマには任意の数のフィールドを含めることができます。各フィールドは MongoDB に格納されているドキュメント内のフィールドを表します。一般的なフィールド型の多くとその宣言方法を示すスキーマの例を以下に示します。

```js
var schema = new Schema({
  name: String,
  binary: Buffer,
  living: Boolean,
  updated: { type: Date, default: Date.now() },
  age: { type: Number, min: 18, max: 65, required: true },
  mixed: Schema.Types.Mixed,
  \_someId: Schema.Types.ObjectId,
  array: [],
  ofString: [String], // 他の型でも配列にすることができます。
  nested: { stuff: { type: String, lowercase: true, trim: true } },
});
```

ほとんどのスキーム型("type:"やフィールド名で記述されるもの)はその名のとおりです。例外は以下のようなものがあります:

* `ObjectId`: データベースのモデルを示すインスタンスです。例えば、本は著者オブジェクトを示すためにこれを使います。一つ一つにはユニークな ID (`_id`) が割り当てられています。必要があれば`populate()`メソッドで関連情報を呼び出すことができます。
* Mixed: 任意のスキーム型。
* []: 項目の配列。このモデルには JavaScript の配列オペレーション(push, pop, unshift, その他。)をオペレートすることができます。上記の例は特別な型なしに`String`オブジェクトの配列を示しています。また、他の型のオブジェクトに対しても配列で持つことはできます。

このコードはフィールドを宣言する 2 つのやり方も示しています:

* フィールドの*name* と *type*を key-value ペアのように書く (例えば `name`, `binary`, `living` のように）.
* `type`定義するオブジェクトが続くフィールド名、およびフィールドの他のオプション。オプションには次のようなものがあります:
    + 初期値.
    + ビルドインのバリデータ (例えば最大値/最小値) それからカスタマイズしたバリデーション機能.
    + そのヒールドが必須かどうか
    + `String` のフィールドは自動的に大文字か、小文字にするか、前後の空白を取り除く（trim）するか？ (例えば:`{ type: String, lowercase: true, trim: true }`)記載することができる）

もっとオプションについて見たいならSchemaTypes (Mongoose docs)を見てみてください.

#### バリデーション

Mongoose はビルドインもしくはカスマイズしたバリデータや同期的もしくは非同期的なバリデータを提供しています。 バリデータはすべての場合において、許容範囲または値と検証失敗のエラーメッセージの両方を指定できます。

ビルドインのバリデータには:

* すべての SchemaTypes に required があります。 これはドキュメントを保存するために必要なフィールドを指定するために使われます。
* Numbers に min（最小値を指定） と max（最大値を指定） バリデータがあります。
* Strings には以下のバリデータがあります:
    + enum: フィールドに利用可能な値の配列を指定します。
    + match: マッチさせる正規表現を指定します。
    + maxlength と minlength: 文字数の最大値と最小値を指定します。

以下の例（Mongoose ドキュメントから少し変更しています）では、いくつかのバリデータタイプとエラーメッセージを指定する方法を示しています:

```js
var breakfastSchema = new Schema({
  eggs: {
    type: Number,
    min: [6, "Too few eggs"],
    max: 12,
    required: [true, "Why no eggs?"],
  },
  drink: {
    type: String,
    enum: ["Coffee", "Tea", "Water"],
  },
});
```

詳しくは Validation (Mongoose docs) を見てみてください。

#### Virtual properties

Virtual properties are document properties that you can get and set but that do not get persisted to MongoDB. The getters are useful for formatting or combining fields, while setters are useful for de-composing a single value into multiple values for storage. The example in the documentation constructs (and deconstructs) a full name virtual property from a first and last name field, which is easier and cleaner than constructing a full name every time one is used in a template.

**メモ:** We will use a virtual property in the library to define a unique URL for each model record using a path and the record's `_id` value.

For more information see Virtuals (Mongoose documentation).

#### Methods and query helpers

A schema can also have instance methods, static methods, and query helpers. The instance and static methods are similar, but with the obvious difference that an instance method is associated with a particular record and has access to the current object. Query helpers allow you to extend mongoose's chainable query builder API (for example, allowing you to add a query "byName" in addition to the `find()`, `findOne()` and `findById()` methods).

### Using models

Once you've created a schema you can use it to create models. The model represents a collection of documents in the database that you can search, while the model's instances represent individual documents that you can save and retrieve.

We provide a brief overview below. For more information see: Models (Mongoose docs).

#### Creating and modifying documents

To create a record you can define an instance of the model and then call `save()`. The examples below assume SomeModel is a model (with a single field "name") that we have created from our schema.

```js
// Create an instance of model SomeModel
var awesome_instance = new SomeModel({ name: "awesome" });

// Save the new model instance, passing a callback
awesome_instance.save(function (err) {
  if (err) return handleError(err);
  // saved!
});
```

Creation of records (along with updates, deletes, and queries) are asynchronous operations — you supply a callback that is called when the operation completes. The API uses the error-first argument convention, so the first argument for the callback will always be an error value (or null). If the API returns some result, this will be provided as the second argument.

You can also use `create()` to define the model instance at the same time as you save it. The callback will return an error for the first argument and the newly-created model instance for the second argument.

```js
SomeModel.create({ name: "also\_awesome" }, function (err, awesome\_instance) {
  if (err) return handleError(err);
  // saved!
});
```

Every model has an associated connection (this will be the default connection when you use `mongoose.model()`). You create a new connection and call `.model()` on it to create the documents on a different database.

You can access the fields in this new record using the dot syntax, and change the values. You have to call `save()` or `update()` to store modified values back to the database.

```js
// Access model field values using dot notation
console.log(awesome_instance.name); //should log 'also\_awesome'

// Change record by modifying the fields, then calling save().
awesome_instance.name = "New cool name";
awesome_instance.save(function (err) {
  if (err) return handleError(err); // saved!
});
```

#### Searching for records

You can search for records using query methods, specifying the query conditions as a JSON document. The code fragment below shows how you might find all athletes in a database that play tennis, returning just the fields for athlete *name* and *age*. Here we just specify one matching field (sport) but you can add more criteria, specify regular expression criteria, or remove the conditions altogether to return all athletes.

```js
var Athlete = mongoose.model("Athlete", yourSchema);

// find all athletes who play tennis, selecting the 'name' and 'age' fields
Athlete.find({ sport: "Tennis" }, "name age", function (err, athletes) {
  if (err) return handleError(err);
  // 'athletes' contains the list of athletes that match the criteria.
});
```

If you specify a callback, as shown above, the query will execute immediately. The callback will be invoked when the search completes.

**メモ:** All callbacks in Mongoose use the pattern `callback(error, result)`. If an error occurs executing the query, the `error` parameter will contain an error document and `result` will be null. If the query is successful, the `error` parameter will be null, and the `result` will be populated with the results of the query.

If you don't specify a callback then the API will return a variable of type Query. You can use this query object to build up your query and then execute it (with a callback) later using the `exec()` method.

```js
// find all athletes that play tennis
var query = Athlete.find({ sport: "Tennis" });

// selecting the 'name' and 'age' fields
query.select("name age");

// limit our results to 5 items
query.limit(5);

// sort by age
query.sort({ age: -1 });

// execute the query at a later time
query.exec(function (err, athletes) {
  if (err) return handleError(err);
  // athletes contains an ordered list of 5 athletes who play Tennis
});
```

Above we've defined the query conditions in the `find()` method. We can also do this using a `where()` function, and we can chain all the parts of our query together using the dot operator (.) rather than adding them separately. The code fragment below is the same as our query above, with an additional condition for the age.
```

Athlete.
  find().
  where('sport').equals('Tennis').
  where('age').gt(17).lt(50).  //Additional where query
  limit(5).
  sort({ age: -1 }).
  select('name age').
  exec(callback); // where callback is the name of our callback function.
```

The find() method gets all matching records, but often you just want to get one match. The following methods query for a single record:

* `findById()`: Finds the document with the specified `id` (every document has a unique `id`).
* `findOne()`: Finds a single document that matches the specified criteria.
* `findByIdAndRemove()`, `findByIdAndUpdate()`, `findOneAndRemove()`, `findOneAndUpdate()`: Finds a single document by `id` or criteria and either update or remove it. These are useful convenience functions for updating and removing records.

**メモ:** There is also a `count()` method that you can use to get the number of items that match conditions. This is useful if you want to perform a count without actually fetching the records.

There is a lot more you can do with queries. For more information see: Queries (Mongoose docs).

#### Working with related documents — population

You can create references from one document/model instance to another using the `ObjectId` schema field, or from one document to many using an array of `ObjectIds`. The field stores the id of the related model. If you need the actual content of the associated document, you can use the `populate()` method in a query to replace the id with the actual data.

For example, the following schema defines authors and stories. Each author can have multiple stories, which we represent as an array of `ObjectId`. Each story can have a single author. The "ref" (highlighted in bold below) tells the schema which model can be assigned to this field.

```js
var mongoose = require("mongoose"),
  Schema = mongoose.Schema;

var authorSchema = Schema({
  name: String,
  stories: [{ type: Schema.Types.ObjectId, ref: "Story" }],
});

var storySchema = Schema({
  author: { type: Schema.Types.ObjectId, ref: "Author" },
  title: String,
});

var Story = mongoose.model("Story", storySchema);
var Author = mongoose.model("Author", authorSchema);
```

We can save our references to the related document by assigning the `_id` value. Below we create an author, then a story, and assign the author id to our stories author field.

```js
var bob = new Author({ name: "Bob Smith" });

bob.save(function (err) {
  if (err) return handleError(err);

  //Bob now exists, so lets create a story
  var story = new Story({
    title: "Bob goes sledding",
    author: bob._id, // assign the \_id from the our author Bob. This ID is created by default!
  });

  story.save(function (err) {
    if (err) return handleError(err);
    // Bob now has his story
  });
});
```

Our story document now has an author referenced by the author document's ID. In order to get the author information in the story results we use `populate()`, as shown below.

```js
Story.findOne({ title: "Bob goes sledding" })
  .populate("author") //This populates the author id with actual author information!
  .exec(function (err, story) {
    if (err) return handleError(err);
    console.log("The author is %s", story.author.name);
    // prints "The author is Bob Smith"
  });
```

**メモ:** Astute readers will have noted that we added an author to our story, but we didn't do anything to add our story to our author's `stories` array. How then can we get all stories by a particular author? One way would be to add our author to the stories array, but this would result in us having two places where the information relating authors and stories needs to be maintained.

A better way is to get the `_id` of our *author*, then use `find()` to search for this in the author field across all stories.

```js
Story.find({ author: bob._id }).exec(function (err, stories) {
  if (err) return handleError(err);
  // returns all stories that have Bob's id as their author.
});
```

This is almost everything you need to know about working with related items *for this tutorial*. For more detailed information see Population (Mongoose docs).

### One schema/model per file

While you can create schemas and models using any file structure you like, we highly recommend defining each model schema in its own module (file), exporting the method to create the model. This is shown below:

```js
// File: ./models/somemodel.js

//Require Mongoose
var mongoose = require("mongoose");

//Define a schema
var Schema = mongoose.Schema;

var SomeModelSchema = new Schema({
  a\_string: String,
  a\_date: Date,
});

//Export function to create "SomeModel" model class
module.exports = mongoose.model("SomeModel", SomeModelSchema);
```

You can then require and use the model immediately in other files. Below we show how you might use it to get all instances of the model.

```js
//Create a SomeModel model just by requiring the module
var SomeModel = require("../models/somemodel");

// Use the SomeModel object (model) to find all SomeModel records
SomeModel.find(callback_function);
```

Setting up the MongoDB database
-------------------------------

Now that we understand something of what Mongoose can do and how we want to design our models, it's time to start work on the *LocalLibrary* website. The very first thing we want to do is set up a MongoDb database that we can use to store our library data.

For this tutorial, we're going to use mLab's free cloud-hosted "sandbox" database. This database tier is not considered suitable for production websites because it has no redundancy, but it is great for development and prototyping. We're using it here because it is free and easy to set up, and because mLab is a popular *database as a service* vendor that you might reasonably choose for your production database (other popular choices at the time of writing include Compose, ScaleGrid and MongoDB Atlas).

**メモ:** If you prefer you can set up a MongoDb database locally by downloading and installing the appropriate binaries for your system. The rest of the instructions in this article would be similar, except for the database URL you would specify when connecting.

You will first need to create an account with mLab (this is free, and just requires that you enter basic contact details and acknowledge their terms of service).

After logging in, you'll be taken to the home screen:

1. Click **Create New** in the *MongoDB Deployments* section.
 ![](/ja/docs/Learn/Server-side/Express_Nodejs/mongoose/mLabCreateNewDeployment.png)
2. This will open the *Cloud Provider Selection* screen.

 ![MLab - screen for new deployment](/ja/docs/Learn/Server-side/Express_Nodejs/mongoose/mLab_new_deployment_form_v2.png)
    * Select the SANDBOX (Free) plan from the Plan Type section.
    * Select any provider from the *Cloud Provider* section. Different providers offer different regions (displayed below the selected plan type).
    * Click the **Continue** button.
3. This will open the *Select Region* screen.

 ![Select new region screen](/ja/docs/Learn/Server-side/Express_Nodejs/mongoose/mLab_new_deployment_select_region_v2.png)
    * Select the region closest to you and then **Continue**.
4. This will open the *Final Details* screen.

 ![New deployment database name](/ja/docs/Learn/Server-side/Express_Nodejs/mongoose/mLab_new_deployment_final_details.png)
    * Enter the name for the new database as `local_library` and then select **Continue**.
5. This will open the *Order Confirmation* screen.

 ![Order confirmation screen](/ja/docs/Learn/Server-side/Express_Nodejs/mongoose/mLab_new_deployment_order_confirmation.png)
    * Click **Submit Order** to create the database.
6. You will be returned to the home screen. Click on the new database you just created to open its details screen. As you can see the database has no collections (data).

 ![mLab - Database details screen](/ja/docs/Learn/Server-side/Express_Nodejs/mongoose/mLab_new_deployment_database_details.png)
 The URL that you need to use to access your database is displayed on the form above (shown for this database circled above). In order to use this you need to create a database user that you can specify in the URL.
7. Click the **Users** tab and select the **Add database user** button.
8. Enter a username and password (twice), and then press **Create**. Do not select *Make read only*.

 ![](/ja/docs/Learn/Server-side/Express_Nodejs/mongoose/mLab_database_users.png)

You have now created the database, and have an URL (with username and password) that can be used to access it. This will look something like: `mongodb://your_user_namer:your_password@ds119748.mlab.com:19748/local_library`.

Install Mongoose
----------------

Open a command prompt and navigate to the directory where you created your skeleton Local Library website. Enter the following command to install Mongoose (and its dependencies) and add it to your **package.json** file, unless you have already done so when reading the Mongoose Primer above.

```bash
npm install mongoose
```

Connect to MongoDB
------------------

Open **/app.js** (in the root of your project) and copy the following text below where you declare the *Express application object* (after the line `var app = express();`). Replace the database url string ('*insert\_your\_database\_url\_here*') with the location URL representing your own database (i.e. using the information from mLab).

```js
//Set up mongoose connection
var mongoose = require("mongoose");
var mongoDB = "insert\_your\_database\_url\_here";
mongoose.connect(mongoDB);
mongoose.Promise = global.Promise;
var db = mongoose.connection;
db.on("error", console.error.bind(console, "MongoDB connection error:"));
```

As discussed in the Mongoose primer above, this code creates the default connection to the database and binds to the error event (so that errors will be printed to the console).

Defining the LocalLibrary Schema
--------------------------------

We will define a separate module for each model, as discussed above. Start by creating a folder for our models in the project root (**/models**) and then create separate files for each of the models:
```

/express-locallibrary-tutorial  //the project root
  /models
    author.js
    book.js
    bookinstance.js
    genre.js
```

### Author model

Copy the `Author` schema code shown below and paste it into your **./models/author.js** file. The scheme defines an author has having `String` SchemaTypes for the first and family names, that are required and have a maximum of 100 characters, and `Date` fields for the date of birth and death.

```js
var mongoose = require("mongoose");

var Schema = mongoose.Schema;

var AuthorSchema = new Schema({
  first\_name: { type: String, required: true, max: 100 },
  family\_name: { type: String, required: true, max: 100 },
  date\_of\_birth: { type: Date },
  date\_of\_death: { type: Date },
});

// Virtual for author's full name
AuthorSchema.virtual("name").get(function () {
  return this.family_name + ", " + this.first_name;
});

// Virtual for author's lifespan
AuthorSchema.virtual("lifespan").get(function () {
  return (
    this.date_of_death.getYear() - this.date_of_birth.getYear()
  ).toString();
});

// Virtual for author's URL
AuthorSchema.virtual("url").get(function () {
  return "/catalog/author/" + this._id;
});

//Export model
module.exports = mongoose.model("Author", AuthorSchema);
```

We've also declared a virtual for the AuthorSchema named "url" that returns the absolute URL required to get a particular instance of the model — we'll use the property in our templates whenever we need to get a link to a particular author.

**メモ:** Declaring our URLs as a virtual in the schema is a good idea because then the URL for an item only ever needs to be changed in one place.
 At this point, a link using this URL wouldn't work, because we haven't got any routes handling code for individual model instances. We'll set those up in a later article!

At the end of the module, we export the model.

### Book model

Copy the `Book` schema code shown below and paste it into your **./models/book.js** file. Most of this is similar to the author model — we've declared a schema with a number of string fields and a virtual for getting the URL of specific book records, and we've exported the model.

```js
var mongoose = require("mongoose");

var Schema = mongoose.Schema;

var BookSchema = new Schema({
  title: { type: String, required: true },
  author: { type: Schema.Types.ObjectId, ref: "Author", required: true },
  summary: { type: String, required: true },
  isbn: { type: String, required: true },
  genre: [{ type: Schema.Types.ObjectId, ref: "Genre" }],
});

// Virtual for book's URL
BookSchema.virtual("url").get(function () {
  return "/catalog/book/" + this._id;
});

//Export model
module.exports = mongoose.model("Book", BookSchema);
```

The main difference here is that we've created two references to other models:

* author is a reference to a single `Author` model object, and is required.
* genre is a reference to an array of `Genre` model objects. We haven't declared this object yet!
### BookInstance model

Finally, copy the `BookInstance` schema code shown below and paste it into your **./models/bookinstance.js** file. The `BookInstance` represents a specific copy of a book that someone might borrow and includes information about whether the copy is available or on what date it is expected back, "imprint" or version details.

```js
var mongoose = require("mongoose");

var Schema = mongoose.Schema;

var BookInstanceSchema = new Schema({
  book: { type: Schema.Types.ObjectId, ref: "Book", required: true }, //reference to the associated book
  imprint: { type: String, required: true },
  status: {
    type: String,
    required: true,
    enum: ["Available", "Maintenance", "Loaned", "Reserved"],
    default: "Maintenance",
  },
  due\_back: { type: Date, default: Date.now },
});

// Virtual for bookinstance's URL
BookInstanceSchema.virtual("url").get(function () {
  return "/catalog/bookinstance/" + this._id;
});

//Export model
module.exports = mongoose.model("BookInstance", BookInstanceSchema);
```

The new things we show here are the field options:

* `enum`: This allows us to set the allowed values of a string. In this case, we use it to specify the availability status of our books (using an enum means that we can prevent mis-spellings and arbitrary values for our status)
* `default`: We use default to set the default status for newly created bookinstances to maintenance and the default `due_back` date to `now` (note how you can call the Date function when setting the date!)

Everything else should be familiar from our previous schema.

### Genre model - challenge!

Open your **./models/genre.js** file and create a schema for storing genres (the category of book, e.g. whether it is fiction or non-fiction, romance or military history, etc).

The definition will be very similar to the other models:

* The model should have a `String` SchemaType called `name` to describe the genre.
* This name should be required and have between 3 and 100 characters.
* Declare a virtual for the genre's URL, named `url`.
* Export the model.
Testing — create some items
---------------------------

That's it. We now have all models for the site set up!

In order to test the models (and to create some example books and other items that we can use in our next articles) we'll now run an *independent* script to create items of each type:

1. Download (or otherwise create) the file populatedb.js inside your *express-locallibrary-tutorial* directory (in the same level as `package.json`).

**メモ:** You don't need to know how populatedb.js works; it just adds sample data into the database.
2. Enter the following commands in the project root to install the *async* module that is required by the script (we'll discuss this in later tutorials, )

```bash
npm install async
```

3. Run the script using node in your command prompt, passing in the URL of your *MongoDB* database (the same one you replaced the *insert\_your\_database\_url\_here* placeholder with, inside `app.js` earlier):

```bash
node populatedb <your mongodb url>
```

4. The script should run through to completion, displaying items as it creates them in the terminal.

**メモ:** **Tip:** Go to your database on mLab. You should now be able to drill down into individual collections of Books, Authors, Genres and BookInstances, and check out individual documents.

まとめ
---

この記事では、Node/Express 上のデータベースと ORM について、また Mongoose のスキーマとモデルの定義方法について多くのことを学びました。次に、この情報を使用して、ローカルライブラリ Web サイト用の `Book`、`BookInstance`、`Author`、および `Genre` を設計および実装しました。

最後に、(スタンドアロンスクリプトを使用して) 多数のインスタンスを作成することによってモデルをテストしました。次の記事では、これらのオブジェクトを表示するためのページの作成について見ていきます。

あわせて参照
------

* Database integration (Express ドキュメント)
* Mongoose website (Mongoose ドキュメント)
* Mongoose Guide (Mongoose ドキュメント)
* Validation (Mongoose ドキュメント)
* Schema Types (Mongoose ドキュメント)
* Models (Mongoose ドキュメント)
* Queries (Mongoose ドキュメント)
* Population (Mongoose ドキュメント)
* 前のページ
* Overview: Express Nodejs
* 次のページ  (en-US)


Express チュートリアル Part 6: フォームの操作 - ウェブ開発を学ぶ

Express チュートリアル Part 6: フォームの操作
===============================

* 前のページ
* Overview: Express Nodejs
* 次のページ  (en-US)

このチュートリアルでは、Pug を使用して Express で HTML フォームを操作する方法、特にデータベースからドキュメントを作成、更新、削除するためのフォームを作成する方法を説明します。

| 前提条件: | Express チュートリアル Part 5: ライブラリデータの表示など、これまでのチュートリアルのトピックをすべて完了してください。 |
| --- | --- |
| 目標: | ユーザからデータを取得するためのフォームの作成方法を理解し、このデータでデータベースを更新する。 |

概要
--

HTML フォームとは、サーバーに送信するためにユーザーから情報を収集するために使用できる Web ページ上の 1 つ以上のフィールド/ウィジェットのグループのことです。テキストボックス、チェックボックス、ラジオボタン、日付選択など、さまざまなタイプのデータを入力するのに適したフォーム入力が用意されているので、フォームを使えばユーザーからの入力を柔軟に収集することが出来ます。また、フォームはサーバとデータを共有するための比較的安全な方法でもあり、クロスサイトリクエストフォージェリ保護機能を使って POST リクエストでデータを送信することができます。

フォームを扱うのは複雑です。開発者はフォーム用の HTML を書き、サーバー上で入力されたデータを検証して特殊文字を置換し、無効なフィールドをユーザーに知らせるためにエラーメッセージを表示してフォームを再度表示し、送信が成功したときにデータを処理し、最後に成功を示す何らかの方法でユーザーに応答しなければなりません。

このチュートリアルでは、上記の操作を Express で実行する方法を紹介します。途中で、サンプルとして地域図書館のウェブサイトを拡張して、ユーザーがライブラリからアイテムを作成、編集、削除できるようにします。

>
> \*\*メモ:\*\*サンプルとして準備されている地域図書館のウェブサイトは認証済みユーザのみに閲覧を制限する方法については書いてないので、現時点ではどのユーザでもデータベースに変更を加えることができます。
>
>
>

### HTML フォーム

最初にHTML フォームの簡単な概要を説明します。ある「チーム」の名前とそれに関連するラベルを入力するための単一のテキストフィールドを持つシンプルな HTML フォームを考えてみましょう。

![Simple name field example in HTML form](/ja/docs/Learn/Server-side/Express_Nodejs/forms/form_example_name_field.png)

フォームは HTML で `<form>...</form>` タグ内の要素の集合として定義され、`type="submit"` の `input` 要素を少なくとも 1 つ含みます。

```html
<form action="/team\_name\_url/" method="post">
  <label for="team\_name">名前を入力してください: </label>
  <input
 id="team\_name"
 type="text"
 name="name\_field"
 value="デフォルトのチーム名." />
  <input type="submit" value="OK" />
</form>
```

ここではチーム名を入力するための 1 つのテキストフィールドだけを含んでいますが、フォームは他の入力要素とそれに関連したラベルをいくつでも含むことができます。フィールドの`type`属性はどのような種類のウィジェットが表示されるかを定義します。フィールドの`name`と`id`は JavaScript/CSS/HTML でフィールドを識別するために使われ、`value`はフィールドが最初に表示されるときの初期値を定義します。マッチングするチームのラベルは、`label`タグ（上記の「名前を入力してください」を参照）を使用して指定され、`for`フィールドには関連する`input`タグの`id`値が含まれます。

`submit` input タグは標準ではボタンとして表示されます。このボタンは、他の`input`要素に含まれるデータをサーバーにアップロードするためにユーザーが押すことができます(この例だと`team_name`だけ)。フォーム属性はデータを送信するために使用される HTTP `method`とサーバー上のデータの送信先(`action`)を定義します。

* `action`: フォームが送信されたときに処理のためにデータが送信される URL です。これが設定されていない場合(または空の文字列が設定されている場合)、フォームは現在のページ URL に戻って送信されます。
* `method`: データを送信するために使用される HTTP メソッド: `POST` または `GET`.
    + `POST`メソッドは、データがサーバのデータベースに変更をもたらす場合は、常に使用されるべきです。なぜならクロスサイトフォージェリ要求攻撃に対してより耐性を持たせることができるからです。
    + `GET`メソッドは、ユーザーデータを変更しないフォーム（検索フォームなど）にのみ使用してください。URL をブックマークや共有できるようにしたい場合におすすめです。
### フォーム処理工程

フォームの処理はモデルに関する情報を表示するために学んだのと同じテクニックをすべて使います: ルートはリクエストをコントローラ関数に送り、モデルからのデータの読み込みを含む必要なデータベースアクションを実行し、HTML ページを生成して返します。さらに複雑なのは、サーバーがユーザーによって提供されたデータを処理し、何か問題があればエラー情報とともにフォームを再表示する必要があるということです。

フォームを含むページのリクエスト（緑色で示されている）から始まる、フォームリクエストを処理するためのプロセスフローチャートを以下に示す。
 ![](/ja/docs/Learn/Server-side/Express_Nodejs/forms/Web%20server%20form%20handling.png)

上の図のように、フォーム処理のコードが必要とする主なものは以下の通りです。

1. ユーザーが最初に要求したときにデフォルトのフォームを表示します。
    * フォームには空白のフィールドが含まれていたり (新しいレコードを作成している場合など)、初期値があらかじめ入力されていたり (レコードを変更している場合や、デフォルトの初期値がある場合など) します。
2. ユーザーから送信されたデータを、通常は HTTP `POST`リクエストで受信します。
3. データを検証し、ハッキング防止のために特殊文字を置換(サニタイズ)します。
4. データが無効な場合は、ユーザーが入力した値と問題のあるフィールドのエラーメッセージをフォームに再表示します。
5. すべてのデータが有効な場合、必要なアクションを実行します（例：データベースにデータを保存する、通知メールを送信する、検索結果を返す、ファイルをアップロードするなど）。
6. すべてのアクションが完了したら、ユーザーを別のページにリダイレクトします。

多くの場合、フォーム処理コードは、フォームの初期表示のための`GET`ルートと、フォームデータの検証と処理のための同じパスへの`POST`ルートを使用して実装されています。これがこのチュートリアルで使用されるアプローチです。

Express 自体はフォーム操作のための特別なサポートを提供していませんが、ミドルウェアを使用してフォームからの `POST` や `GET`パラメータを処理したり、それらの値を検証/サニタイズしたりすることができます。

### 検証とサニタイズ

フォームからのデータが保存される前に、それは検証され、サニタイズされなければなりません。

* 入力された値が各フィールドに対して適切であるか（正しい範囲、フォーマットなど）、およびすべての必須フィールドに対して値が提供されているかどうかを確認します。
* サニタイズは、悪意のあるコンテンツをサーバーに送信するために使用される可能性のあるデータ内の文字を削除したり、置換したりします。

このチュートリアルでは、人気のある express-validator モジュールを使ってフォームデータの検証とサニタイズを行います。

#### インストール

プロジェクトのルートで以下のコマンドを実行してモジュールをインストールします。

```bash
npm install express-validator
```

#### express-validator の使用

**メモ:** Github のexpress-validatorガイドに API の概要が書かれています。(カスタムバリデータの作成を含む) すべての機能を知るには、これを読むことをお勧めします。以下では、サンプルの「地域図書館」にとって有用なサブセットだけを取り上げます。

コントローラでバリデータを使うには、以下のように **'express-validator/check'** と \*\*'express-validator/filter'\*\*モジュールから使いたい関数を要求(require)しなければなりません。

```js
const { body, validationResult } = require("express-validator/check");
const { sanitizeBody } = require("express-validator/filter");
```

多くの関数が用意されており、リクエストパラメータ、body、ヘッダー、Cookie などのデータをチェックしてサニタイズすることができますし、一度にすべてのデータをチェックしてサニタイズすることもできます。このチュートリアルでは、主に`body`、`sanitizeBody`、`validationResult`を使用します。

機能は以下のように定義されています。

* `body(fields[, message])`: テストに失敗した場合に表示されるオプションのエラーメッセージとともに検証するリクエストボディ (`POST`パラメータ) のフィールドのセットを指定します。検証基準は、`body()`メソッドにデイジーチェーンで接続されています。例えば、以下の最初のチェックでは「name」フィールドが空でないことをテストし、空の場合は「Empty name」というエラーメッセージを設定します。2 番目のテストでは、年齢フィールドが有効な日付であるかどうかをチェックし、`optional()` を使用して null や空の文字列を指定しても検証に失敗しないようにしています。

```js
body('name', 'Empty name').isLength({ min: 1 }),
body('age', 'Invalid age').optional({ checkFalsy: true }).isISO8601(),
```

また、異なるバリデータをデイジーチェーン化して、前のバリデータが真の場合に表示されるメッセージを追加することもできます。

```js
body('name').isLength({ min: 1 }).trim().withMessage('Name empty.')
    .isAlpha().withMessage('Name must be alphabet letters.'),
```

**メモ:** また、上記のように `trim()` のようなインラインサニタイザーを追加することもできます。しかし、ここで適用されるサニタイザは検証ステップにのみ適用されます。最終的な出力をサニタイザ処理したい場合は、以下のように別のサニタイザメソッドを使用する必要があります。
* `sanitizeBody(fields)`: サニタイズするフィールドを指定します。サニタイズ操作は、このメソッドにデイジーチェーン接続されます。例えば、以下の `escape()` サニタイズ操作は、JavaScript のクロスサイトスクリプティング攻撃で使用される可能性のある HTML 文字（例えば「'」、「"」、「&」など）を name 変数から削除します。

```js
sanitizeBody('name').trim().escape(),
sanitizeBody('date').toDate(),
```

* `validationResult(req)`: Runs the validation, making errors available in the form of a `validation` result object. This is invoked in a separate callback, as shown below:

```js
(req, res, next) => {
  // Extract the validation errors from a request.
  const errors = validationResult(req);

  if (!errors.isEmpty()) {
    // There are errors. Render form again with sanitized values/errors messages.
    // Error messages can be returned in an array using `errors.array()`.
  } else {
    // Data from form is valid.
  }
};
```

We use the validation result's `isEmpty()` method to check if there were errors, and its `array()` method to get the set of error messages. See the Validation Result API for more information.

The validation and sanitization chains are middleware that should be passed to the Express route handler (we do this indirectly, via the controller). When the middleware runs, each validator/sanitizer is run in the order specified.

We'll cover some real examples when we implement the *LocalLibrary* forms below.

### Form design

Many of the models in the library are related/dependent—for example, a `Book` *requires* an `Author`, and *may* also have one or more `Genres`. This raises the question of how we should handle the case where a user wishes to:

* Create an object when its related objects do not yet exist (for example, a book where the author object hasn't been defined).
* Delete an object that is still being used by another object (so for example, deleting a `Genre` that is still being used by a `Book`).

For this project we will simplify the implementation by stating that a form can only:

* Create an object using objects that already exist (so users will have to create any required `Author` and `Genre` instances before attempting to create any `Book` objects).
* Delete an object if it is not referenced by other objects (so for example, you won't be able to delete a `Book` until all associated `BookInstance` objects have been deleted).

**メモ:** A more "robust" implementation might allow you to create the dependent objects when creating a new object, and delete any object at any time (for example, by deleting dependent objects, or by removing references to the deleted object from the database).

### Routes

In order to implement our form handling code, we will need two routes that have the same URL pattern. The first (`GET`) route is used to display a new empty form for creating the object. The second route (`POST`) is used for validating data entered by the user, and then saving the information and redirecting to the detail page (if the data is valid) or redisplaying the form with errors (if the data is invalid).

We have already created the routes for all our model's create pages in **/routes/catalog.js** (in a previous tutorial (en-US)). For example, the genre routes are shown below:

```js
// GET request for creating a Genre. NOTE This must come before route that displays Genre (uses id).
router.get("/genre/create", genre_controller.genre_create_get);

// POST request for creating Genre.
router.post("/genre/create", genre_controller.genre_create_post);
```

Express forms subarticles
-------------------------

The following sub articles will take us through the process of adding the required forms to our example application. You need to read and work through each one in turn, before moving on to the next one.

1. Create Genre form (en-US) — Defining a page to create `Genre` objects.
2. Create Author form (en-US) — Defining a page to create `Author` objects.
3. Create Book form (en-US) — Defining a page/form to create `Book` objects.
4. Create BookInstance form (en-US) — Defining a page/form to create `BookInstance` objects.
5. Delete Author form (en-US) — Defining a page to delete `Author` objects.
6. Update Book form (en-US) — Defining page to update `Book` objects.
Challenge yourself
------------------

Implement the delete pages for the `Book`, `BookInstance`, and `Genre` models, linking them from the associated detail pages in the same way as our *Author delete* page. The pages should follow the same design approach:

* If there are references to the object from other objects, then these other objects should be displayed along with a note that this record can't be deleted until the listed objects have been deleted.
* If there are no other references to the object then the view should prompt to delete it. If the user presses the **Delete** button, the record should then be deleted.

A few tips:

* Deleting a `Genre` is just like deleting an `Author` as both objects are dependencies of `Book` (so in both cases you can delete the object only when the associated books are deleted).
* Deleting a `Book` is also similar, but you need to check that there are no associated `BookInstances`.
* Deleting a `BookInstance` is the easiest of all because there are no dependent objects. In this case, you can just find the associated record and delete it.

Implement the update pages for the `BookInstance`, `Author`, and `Genre` models, linking them from the associated detail pages in the same way as our *Book update* page.

A few tips:

* The *Book update page* we just implemented is the hardest! The same patterns can be used for the update pages for the other objects.
* The `Author` date of death and date of birth fields and the `BookInstance` due\_date field are the wrong format to input into the date input field on the form (it requires data in form "YYYY-MM-DD"). The easiest way to get around this is to define a new virtual property for the dates that formats the dates appropriately, and then use this field in the associated view templates.
* If you get stuck, there are examples of the update pages in the example here.
まとめ
---

NPM の Express、Node、およびサードパーティのパッケージは、Web サイトにフォームを追加するために必要なすべてを提供します。この記事では、Pug を使用してフォームを作成する方法、express-validator を使用して入力を検証およびサニタイズする方法、およびデータベース内のレコードを追加、削除、および変更する方法を学びました。

これで、基本的なフォームとフォーム処理コードを自分の Node Web サイトに追加する方法を理解したはずです。

あわせて参照
------

* express-validator (npm ドキュメント).
* 前のページ
* Overview: Express Nodejs
* 次のページ  (en-US)


Express チュートリアル Part 5: ライブラリデータの表示 - ウェブ開発を学ぶ

Express チュートリアル Part 5: ライブラリデータの表示
===================================

* 前のページ  (en-US)
* Overview: Express Nodejs
* 次のページ

これで地域図書館の Web サイトの書籍やその他のデータを表示するページを追加する準備が整いました。このページには、各モデルタイプのレコード数と、すべてのモデルのリストおよび詳細ページを示すホームページが含まれます。その過程で、データベースからレコードを取得したり、テンプレートを使用したりする際の実際的な経験を積むことになります。

| 前提条件: | 以前のチュートリアルのトピック (Express チュートリアル Part 4: ルートとコントローラ (en-US)を含む) を完了してください。 |
| --- | --- |
| 目標: | async モジュールと Pug テンプレート言語の使い方、そしてコントローラ関数の URL からデータを取得する方法を理解すること。 |

概要
--

前回のチュートリアル記事では、データベースとやり取りするために使用できる Mongoose モデルを定義し、いくつかの初期ライブラリレコードを作成しました。その後、LocalLibrary Web サイトに必要なすべてのルートを作成しました (en-US)が、"ダミーコントローラ" 関数 (ページにアクセスすると "未実装" のメッセージを返すだけのスケルトンコントローラ関数) を使用しました。

次のステップは、私たちの図書館情報を表示するページに適切な実装をすることです (後の記事で情報を作成、更新、または削除するフォームを特徴とする実装ページを見ます)。これには、モデルを使用してレコードを取得するためのコントローラ機能の更新、およびこの情報をユーザに表示するためのテンプレートの定義が含まれます。

はじめに、コントローラ関数で非同期操作を管理する方法と Pug を使用してテンプレートを作成する方法を説明する概要/入門トピックを提供します。それから、主要な "読み取り専用" ページのそれぞれに、それらが使用する特別な機能や新しい機能についての簡単な説明を付けて実装を提供します。

この記事が終わるときには、ルート、非同期関数、ビュー、およびモデルが実際にどのように機能するのかについてのエンドツーエンドの理解が十分にあるはずです。

ライブラリデータチュートリアルサブ記事の表示
----------------------

次のサブ記事では、必要な Web サイトページを表示するために必要なさまざまな機能を追加するプロセスについて説明します。次のものに進む前に、順番にこれらのそれぞれを読み、作業する必要があります。

1. async を使用した非同期フロー制御
2. テンプレートプライマー (en-US)
3. LocalLibrary 基本テンプレート
4. ホームページ (en-US)
5. ブックリストページ (en-US)
6. ブックインスタンスリストページ (en-US)
7. moment を使用した日付のフォーマット (en-US)
8. 著者リストページとジャンルリストページのチャレンジ (en-US)
9. ジャンル詳細ページ (en-US)
10. 本の詳細ページ (en-US)
11. 著者詳細ページ
12. ブックインスタンス詳細ページとチャレンジ (en-US)
まとめ
---

これで、サイトのすべての "読み取り専用" ページを作成しました。各モデルのインスタンスの数を表示するホームページ、および書籍、書籍のインスタンス、作家、ジャンルのリストと詳細ページです。その過程でコントローラ、非同期操作を使用したときのフロー制御の管理、Pug を使用したビューの作成、モデルを使用したデータベースの照会、ビューからテンプレートへの情報の受け渡し方法などについて多くの基礎知識を得て、そしてテンプレートを作成および拡張しました。チャレンジを完了した人たちはまた、moment を使った日付処理について少し学んだことでしょう。

次回の記事では、サイトに格納されているデータの変更を開始するための HTML フォームとフォーム処理コードを作成して、私たちの知識に基づいて構築します。

あわせて参照
------

* Async module (Async ドキュメント)
* Using Template engines with Express (Express ドキュメント)
* Pug (Pug ドキュメント)
* Moment (Moment ドキュメント)
* 前のページ  (en-US)
* Overview: Express Nodejs
* 次のページ


LocalLibrary 基本テンプレート - ウェブ開発を学ぶ

LocalLibrary 基本テンプレート
=====================

Now that we understand how to extend templates using Pug, let's start by creating a base template for the project. This will have a sidebar with links for the pages we hope to create across the tutorial articles (e.g. to display and create books, genres, authors, etc.) and a main content area that we'll override in each of our individual pages.

Open **/views/layout.pug** and replace the content with the code below.

```pug
doctype html
html(lang='en')
  head
    title= title
    meta(charset='utf-8')
    meta(name='viewport', content='width=device-width, initial-scale=1')
    link(rel='stylesheet', href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css')
    script(src='https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js')
    script(src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js')
    link(rel='stylesheet', href='/stylesheets/style.css')
  body
    div(class='container-fluid')
      div(class='row')
        div(class='col-sm-2')
          block sidebar
            ul(class='sidebar-nav')
              li
                a(href='/catalog') Home
              li
                a(href='/catalog/books') All books
              li
                a(href='/catalog/authors') All authors
              li
                a(href='/catalog/genres') All genres
              li
                a(href='/catalog/bookinstances') All book-instances
              li
                hr
              li
                a(href='/catalog/author/create') Create new author
              li
                a(href='/catalog/genre/create') Create new genre
              li
                a(href='/catalog/book/create') Create new book
              li
                a(href='/catalog/bookinstance/create') Create new book instance (copy)

        div(class='col-sm-10')
          block content
```

The template uses (and includes) JavaScript and CSS from Bootstrap to improve the layout and presentation of the HTML page. Using Bootstrap or another client-side web framework is a quick way to create an attractive page that can scale well on different browser sizes, and it also allows us to deal with the page presentation without having to get into any of the details—we just want to focus on the server-side code here!

The layout should be fairly obvious if you've read our above Template primer. Note the use of `block content` as a placeholder for where the content for our individual pages will be placed.

The base template also references a local css file (**style.css**) that provides a little additional styling. Open **/public/stylesheets/style.css** and replace its content with the following CSS code:

```css
.sidebar-nav {
  margin-top: 20px;
  padding: 0;
  list-style: none;
}
```

When we get round to running our site, we should see the sidebar appear! In the next sections we will use the above layout to define the individual pages.

Next steps
----------

* Return to Express Tutorial Part 5: Displaying library data.
* Proceed to the next subarticle of part 5: Home page (en-US).


著者詳細ページ - ウェブ開発を学ぶ

著者詳細ページ
=======

著者詳細ページには、指定された `Author` に関する情報を、その (自動的に生成された) `_id` フィールド値を使用して識別し、その `Author` に関連するすべての `Book` オブジェクトのリストを表示する必要があります。

Controller
----------

Open **/controllers/authorController.js**.

Add the following lines to the top of the file to import the *async* and *Book* modules (these are needed for our author detail page).

```js
var async = require("async");
var Book = require("../models/book");
```

Find the exported `author_detail()` controller method and replace it with the following code.

```js
// Display detail page for a specific Author.
exports.author\_detail = function (req, res, next) {
  async.parallel(
    {
      author: function (callback) {
        Author.findById(req.params.id).exec(callback);
      },
      authors\_books: function (callback) {
        Book.find({ author: req.params.id }, "title summary").exec(callback);
      },
    },
    function (err, results) {
      if (err) {
        return next(err);
      } // Error in API usage.
      if (results.author == null) {
        // No results.
        var err = new Error("Author not found");
        err.status = 404;
        return next(err);
      }
      // Successful, so render.
      res.render("author\_detail", {
        title: "Author Detail",
        author: results.author,
        author\_books: results.authors_books,
      });
    },
  );
};
```

The method uses `async.parallel()` to query the `Author` and their associated `Book` instances in parallel, with the callback rendering the page when (if) both requests complete successfully. The approach is exactly the same as described for the *Genre detail page* above.

View
----

Create **/views/author\_detail.pug** and copy in the following text.

```js
extends layout

block content

  h1 Author: #{author.name}
  p #{author.date_of_birth} - #{author.date_of_death}

  div(style='margin-left:20px;margin-top:20px')

    h4 Books

    dl
      each book in author_books
        dt
          a(href=book.url) #{book.title}
        dd #{book.summary}

      else
        p This author has no books.
```

Everything in this template has been demonstrated in previous sections.

What does it look like?
-----------------------

Run the application and open your browser to http://localhost:3000/. Select the *All Authors* link, then select one of the authors. If everything is set up correctly, your site should look something like the following screenshot.

![Author Detail Page - Express Local Library site](/ja/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Author_detail_page/LocalLibary_Express_Author_Detail.png)

**メモ:** The appearance of the author *lifespan* dates is ugly! We'll address that in the final challenge in this article.

Next steps
----------

* Return to Express Tutorial Part 5: Displaying library data.
* Proceed to final subarticle of part 5 : BookInstance detail page and challenge (en-US).