TypeScript でつくるシングルページアプリケー ー import * as fs from ' fs' export class DbConfigManager { stat i c i n i t i a ⅱ ze ( ) : VO i d { pr ivate static dbConfig: mysql. lConnectionConfig, シ・ヨン const data = fs. readFiIeSync(' . /json/db config. json DbConfigManager. dbConfig = JSON. parse(data) ; static getConfig() : mysql. lConnectionConfig { i f ( ! DbConf i gManager. dbConf i g) { throw new Er ror ( ' D i d not i n i t i a ⅱ zed ド ) ; return DbConfigManager. dbConfig, ンスタンスの初期化も行っています。 容で index. ts ファイルを作成します。この index. ts 内では、 4 行目でデータベース接続設イ 次に web サーバー起動処理を書いていきます。『 www 』ディレクトリ内に、リスト 4.1.3 の内 リスト 4.2.3.3 server/www/index. ts 〃省略 index. ts / / Web サーバー起動処理 〃省略 server/ サーバー側プロジェクト用ディレクトリ ト client/ フロント側プロジェクト用ディレクトリ chapter-4/ import * as http from ' http . /app import app from import { DbConf i gManager } from DbConfigManager. initialize() : . /conf i g/DbConf i gManager = http. createServer (app) ; const server const port = normalizePort(process. env. PORT Ⅱ server. listen(port) ; onError) ; server. on(' error 19 ' 3000 ' ) ;
TypeScript でつくるシングノレベージアプリケーション function onListening() const addr = server. address() ; * Event listener for HTTP server "listening string console.log(addr + bind) ; port ' + addr. port, ? p i pe + add r const bind = typeof addr event. 次に、リスト 4.2.3.3 の 2 行目で参照している app. ts をリスト 4.1.3.4 の内容で作成します。 ー chapter-4/ ト client/ server/ 〃省略 L app. フロント側プロジェクト用ディレクトリ サーバー側プロジェクト用ディレクトリ ts リスト 4.2.3.4 server/app. ts import * as bodyParser from body-parser e 」 S * as express from express import * as path from path * as favicon from serve—favicon import api from . /routes/api' index from . /routes/index import import import import 21 app. set(' view engine ejs'); app. set(' views d i rname 十 ' /V i ews' ) : 〃テンプレートエンジンに ejs を使用するための設定 app. use(favicon(—di rname + ' /public/favicon. png' ) ) ; 〃フアビコンを設定 const app = express ( ) ; * @type {Express) * Express アプリケーションオプジェクト
TypeScript でつくるシングルページアプリケー export defau は i ndex , シ・ヨン リスト 4.2.2.2 server/routes/index. ts import * as express from express import vl from ' . / vl ' const api api . use('/vl' = express. Router ( ) ; export default api ; リスト 4. 1.2.3 server/routes/index. ts export default vl : a rt i c 尾 ) : vl. use('/article' = express. Router() ; const vl import article from . /article import * as express from express リスト 4.2.2.4 server/routes/index. ts import * as express from express import { ArticIeController } from const article = express. Router ( ) : . /.. /.. /contr011ers/ArticleControIIer article. get('/' , (req, res, next) = > { const articleController ニ new ArticleController() ; articIeControIIer. index(req, res, next) ; article. get('/all . json (req, res, next) = > { const articleController = new ArticleController() ; articIeContr011er. all (req, res, next) ; article. post('/' , (req, res, next) = > { const articIeController = new ArticleController() ; articIeController. create(req, res, next) : 24
name ve r S ー on scripts "build" rimraf .. /server/public & & webpack —colors' —progress "build:prod" "NODE_ENV=production rimraf .. /server/public & & webpack —progress —colors ・ bu ⅱ d-aot" rimraf .. /server/public & & webpack —progress ——colors ——config ー webpack. config. aot. js' "build-aot:prod' NODE_ENV=production rimraf .. /server/public & & webpack ー —colors —config webpack. config. aot. js" —progress dev" webpack -col ors --watch —progress sampl e—crud—app ⅱ cat i on—c ⅱ ent " 1 . 0.0 " 'license "MIT" dependencies "@angul ar/common " ~ 2.4. 8 " "@angul ar/comp Ⅱ er' " ~ 2.4. 8 " "@angul ar/core " ~ 2.4. 8 " "@angul ar/forms " ~ 2.4. 8 " "@angul ar/http" " ~ 2.4. 8 " "@angul ar/pl atform—browser " ~ 2.4.8 " "@angul ar/pl atform-browser-dynam i c "@angul ar/router " ~ 3.4.0 " "@angul ar/upgrade " ~ 2.4. 8 " angu ー ar— i n—memory—web—ap i ー 2.4. 1 " core—」 S 」 query ref lect-metadata' rx 」 S " . 1. 2 " toastr zone. 」 S " ~ 2.4.8 " " ~ 0. 2.4 " "AO. 7. 7 " devDependenc i es "@angul ar/comp Ⅱ er—c ⅱ " " . 4.8 " "@ngtool s/webpack' 1 . 2. 10 " "@types/jquery " 貶 . 0.40 " "@types/ref lect-metadata' "@types/rx" "@types/toastr" " . 1 . 32 " "@types/zone. js " 8.0. 27 " angul ar2-tempI ate- loader" copy—webpack—pl ugi n " 8.5. 1 " raw—loader ー 2. 6. 1 " r imraf" 'ts-loader" typescr i pt" " 貶 . 2. 1 " webpack " 8.0. 5 " " 0. 6. 2 " " . 2. 1 " 38
TypeScript でつくるシングノレベージアプリケー シ・ヨン インストールします。 リスト 4. 2. 2. 3 $ npm install リスト 4.2.2.2 のコマンドを実行すると、 package. 」S0Ⅱの dependencies と devDependencies で管理されている npm モジュールがインストールされます。 4.2.3 実装 まず MySQL に接続するための設定を保持するためのファイルを作ります。今回は設定を json ディレクトリ内に db—config. json というファイル名で JSON ファイルを作成します。ファイ ルを作成したら以下のように、 host 、 port 、 user 、 password 、 database に、自身のデータベ ースの接続情報を記述し保存します。 ー chapter-4/ ト client/ フロント側プロジェクト用ディレクトリ server/ サーバー側プロジェクト用ディレクトリ conf ー L DbConfigManager. ts 〃 〃省略 ト json/ L db conf i g. json / / データベースへの接続設定ファイル / / 省略 リスト 4.2.3. 1 server/json/db_confoig. 」 son ・ host" localhost" 3306 , port root" user 'hogehoge password 'database" sampl e—crud—app—db" データベース接続情報のファイルを作成したら、次に接続情報の設定を保持するためのク ラスを作成します。 リスト 4.2.3.2 server/config/DbConfigManager. ts ー lmport * as mysql from mysql' 18
TypeScript でつくるシングルページアプリケーション server. on(' listening , onListening) : * Normalize a port intO a number, string, function normalizePort(val: string) { const port = parselnt(val 10 ) ; Event listener for HTTP server error function onError (error: any) { if (error. syscall ⅱ sten' ) if (isNaN(port)) { 〃 named pipe return val, if (port 〉 = 0 ) { / / port number return port, return false, or false. event. throw error, const b i nd ニ typeof port = ? P i pe + port Port ' + port; string / / handle specific listen errors with friendly messages switch (error. code) { case ' EACCES' console. error(bind 十 ' process. exit(l) ; break, case ' EADDRINUSE' console. error(bind 十 ' process. exit(l) : break, default . throw error; requires elevated privileges') : i s 引 ready i n use' ) ; 20
TypeScript でつくるシングルページアプリケーション 4 章シンクルペーシアプリケーションの作成 2 章でごく簡単なプログラムを TypeScript を用いて作成し、 3 章で TypeScript の代表的 な機能を確認しました。 4 章では以下のような機能を持った記事管理シングルページアプリケ ーションを作成します。 記事の投稿 記事の閲覧 記事の更新 記事の削除 4 章ではサーバーサイド、フロントエンドそれぞれに以下のフレームワークを使用します。 Express Node. js 用 Web アプリケーションフレームワークです。 Angular2 Google が開発を主導しているフロントエンド web アプリケー ションフレームワー クです。 なお、本書ではワーキングディレクトリとして『 chapter - 4 』という名前のディレクトリ下で作業 する前提で進めます。さらに、『 chapter -4 』ディレクトリの下に『 clie Ⅱ t 』ディレクトリと『 server 』 ディレクトリの、 2 つのディレクトリを作成します。これはそれぞれ、フロント側のプロジェクト、サ ーバー側のプロジェクト用のディレクトリとなります。 ー chapter-4/ ト client/ フロント側プロジェクト用ディレクトリ server/ サーバー側プロジェクト用ディレクトリ 図 4.1 ~ 4.4 は完成形の画面イメージです。 0 12
TypeScript でつくるシングルページアプリケー (req, res, next) = > { article. get(' /count. json const articleControIIer = new ArticIeController(); articIeControIIer. count(req, res, next) : (req, res, next) = > { article. PUt('/: idY. json' const articleControIIer ニ new ArticleController() : articIeContr011er. update(req, res, next) ; (req, res, next) = > { article. delete('/:idY. json const articleControIIer = new ArticleContr011er() ; articIeController. delete(req, res, next) ; (req, res, next) = 〉 { article. get('/:id%. json const articleController = new ArticIeContr011er() ; articIeController. read(req, res, next) ; export default article, 4.2.3 モデルの作成 シ ' ョン・ 次はモデルを作成します。ここで言うモデルとは、デーテべースに格納される 1 っ 1 つのレ コードの各カラムの属性を持っクラスまたはインタフェースのことを指します。所謂ビジネスロジ ックのことではなく、また、データベースへアクセスするための機能も持ちません。 また、今回はサンプル・アプリケーション全体で使用する AppError クラスも models ディレ クトリに置いてしまいます。他にもエラー系のクラスが増えるようであれば errors や exceptio Ⅱ s などの名前でディレクトリを作成し、そこに置くべきでしよう。 25 リスト 4.2.3.2 server/models/RegisteredArticle. ts bOdy: string, t i 目 e : st r i ng , export interface Article { * 記事インタフェース リスト 4.2.3. 1 server/modeIs/Article. ts
TypeScript でつくるシングルページアプリケーション updatedAt: string createdAt : str i ng, id: number, export interface RegisteredItem { * 登録済情報インタフェース リスト 4.2.3.3 server/models/RegisteredArticle. ts export interface RegisteredArticle extends Article, RegisteredItem { * 登録済記事インタフェース import { RegisteredItem } from ". /RegisteredItem' import { ArticIe } from ". /Article" ます。サンプルアプリのエラーベージなので、単純にステータスコードとエラーメッセージを表 工ラーベージ用のテンプレートを作成します。今回はテンプレートエンジンに EJS を使用し 4.2.4 工ラーベーシ用テンプレートの作成 示するだけの簡素なものを作ります。 く /htm レ く /body> く /d i v> く %-status%> く %-message%> <d i v> く body> く /head> く t i 目 e>ERROR ーく %-status%> く /t i 目 e> く meta http-equ i v="X-UA-Compat i 国 e" content=" i e=edge"> initia ト scale=l. 0 , maximum-scale=l. 0 , minimum-scale=l. 0 " > <meta name= v i ewport" content= 'wi dth=dev i ce—wi dth, user—scal ab 尾 = no , <meta charset="UTF-8"> く head> <html lang="ja"> く !doctype htm リスト 4.2.5 server/views/error. e 」 s 26
TypeScript でつくるシングルページアプリケー 以下の URL で各 API を呼び出します。 シ ' ョン ソースコード上は、それぞれコントローラの対応するメソッドを呼び出しています。 記事データを削除する。 十 DELTE メソッド 記事データを更新する。 ◆ PUT メソッド 記事データを返す ◆ GET メソッド http://ドメイン : ポート番号 /api/vl/article/ + 記事データの ID + . json 記事データー覧を返す。 ◆ PPOST メソッド http://ドメイン : ポート番号 /api/vl/article/ イルを作成します。ルーティングの設定には Express. Router の get, post, put, delete など 以上の処理を、 URL の階層構造と同じように以下の構成で、ディレクトリと TypeScript ファ のメソッドと use メソッドを使用します。 L server/ サーバー側プロジェクト用ディレクトリ ト client/ フロント側プロジェクト用ディレクトリ chapter-4/ ト routes/ 〃略 ート ap i / リスト 4.2.2. 1 server/routes/index. ts ー index. ts L- index. tS ー L index. ts ート art i c 尾 . ts 〃略 import * as path from path' import * as express from express const const r e S. index. index. i ndex. index. = express. Router() ; i ndex (req: express. Request, res: express. Response) send I ndexHtml ' i ndex. htm ド ) ) ; public' sendFiIe(path. join(—di rname, sendIndexHtml) : sendIndexHtmI) : get(' /createArticIe sendIndexHtmI) ; get(' /updateArticle/: id' sendIndexHtmI) ; get('/viewArticle/:id 23