20200314のNode.jsに関する記事は7件です。

Vue.jsプロジェクトのセットアップ

Vue.jsのプロジェクトを最初から作る手順を紹介します。

前提条件

  • npm、yarnがインストール済みであること

@vue/cliのインストール

グローバルに@vue/cliをインストールしてvueコマンドを使用できるようにします。

$ npm install -g @vue/cli

vueプロジェクトの作成

$ vue create project-name
? Please pick a preset: (Use arrow keys)
❯ default (babel, eslint) 
  Manually select features 

開発環境の起動

$ yarn serve

起動後、ブラウザからhttp://localhost:8080/で表示できます。

production用build

$ yarn build

成功すると、distディレクトリにファイルが作られます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

express-generatorでアプリを作成したらインストールするモジュール

モジュール

  • express-session
  • express-validator
  • mysql
  • knex
  • bookshelf

インストール方法

npm install --save モジュール

参考

node.js超入門 p376

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

express-generatorでアプリを作成したらする事

モジュール読み込むモジュール

  • express-session
  • express-validator
  • mysql
  • knex
  • bookshelf

インストール方法

npm install --save モジュール

app.jsの追記

var bodyParser = require('body-parser');
var session = require('express-session');
var validator = require('express-validator');

app.use(validator());

var session_opt = {
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: false,
  cookie: {maxAge: 60 * 60 * 1000}
};
app.use(session(session_opt));

routesの中に新しくjsのファイルを追加する場合は、上記に追加して下記も追加する。

var hoge = require('./routes/追加したファイル名');

app.use('/パス名', hoge);

※hoge、追加したファイル名、パス名は同じにすると分かりやすい

参考

node.js超入門 p376

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

3分で分かる。MERNスタックを簡単に説明してみる

MERNスタックの仕組みと、参考になるチュートリアルを提供する記事です。本当に重要な部分のみを扱いました。

MERNスタックとは

MongoDB, Express, React.js, Node.jsの4つを使ったソフトウェアハンドル。Webアプリ開発に用いられる。仮に、React.jsではなく、Angular.jsを使う場合、MEANスタックとなる。

MongoDB:ドキュメント志向のNo-SQLデータベース。データの保存などに使う。DBは、データベースの意。
ExpressJS:Node.jsのフレームワーク。Node.jsの機能と一緒に使う事で、バックエンドの構築が出来る。
ReactJS:単一ページWebアプリのUIを作成するUIコンポーネントを構築出来る。アプリケーションのView部分を担っている。
NodeJS:サーバーサイドでも動くjavascriptってカッコイイし楽だよね、と覚えておこう。

何が良いのか

フルスタックエンジニアを名乗りたい人は、実はjavascriptが書ける時点で完結できてしまう。企業側から捉えると、サーバーサイドエンジニアの人手が足りなくても、開発案件がMERN構築で可能な場合、フロントエンドエンジニアをそのままサーバーサイドに。というアサインも可能かもしれない。

実際の中身

2020-03-14 15.10.51.png

ユーザーは、アプリケーションのView(UI部分)と繋がっている。ReactとExpressはどちらもNode.jsで作成されている。この2つのコンポーネントは、RESTful APIを経由して通信している。

例)データを送信したいと思い、送信ボタンをクリックした場合:
クライアントPC
→ReactJSを経由
→NodeJSベースのExpressサーバーに送信
→MongoDB

にいく。

例)データを取得したいと思い、ボタンをクリックした場合;
MongoDB
→NodeJSベースのExpressサーバーに送信
→ReactJSを経由
→クライアントPC

にいく。

MERNスタックを構築してみたい、という方へ

実際にどんなTutorialがあるか調べてみました。

Learn the MERN Stack - Full Tutorial (MongoDB, Express, React, Node.js)
https://www.youtube.com/watch?v=7CqJlxBYj-M
英語だけど、一番簡単なMERNアプリを作っている気がします。

The MERN Stack Tutorial – Building A React CRUD Application From Start To Finish
https://codingthesmartway.com/the-mern-stack-tutorial-building-a-react-crud-application-from-start-to-finish-part-1/
こちらも英語です。youtubeにも上がっているけど、ちょっと動画は・・・って方はこちらがイイかも。

MERN Stack Front To Back: Full Stack React, Redux & Node.js
https://www.udemy.com/course/mern-stack-front-to-back/
英語です。有料のUdemyですが、こちらは実際に作ってみました。ReactもHooks使ったりとモダンに扱っていたため、筆者としてはオススメです。

まとめ

実際に作成しようとなった場合、ドキュメントが少ない、そもそも日本語で書かれたMERNのチュートリアルが見つからない、と色々と不安な点はあると感じます。しかし、Javascriptのみで書けるという利点は大きいです。

最近のReactJSは、使用傾向が高いということ
Microsoft, Yahooなど、NodeJSの推薦会社が大きいこと

などを踏まえると、一度自作のアプリケーションを作ってみてもイイかと思います。

参考にした資料

What is MERN Stack?
https://www.educative.io/edpresso/what-is-mern-stack
Node.jsのMVCフレームワーク「Express」の基礎知識とインストール (1/3)
https://www.atmarkit.co.jp/ait/articles/1503/04/news047.html#011
初心者向け!3分で理解するNode.jsとは何か?
https://eng-entrance.com/what-is-nodejs

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Sequelize(PostgreSQL)で月次の集計を行う

例えば、特定の会社に所属するアカウントの新規作成数を月次で集計したい場合(そんな状況があるのかどうかはさておき)

想定結果

month cnt
2020-03 10

PostgreSQL

SELECT 
TO_CHAR(created_date, 'YYYY-mm') AS month,
COUNT(user_id) AS created_cnt
FROM users
WHERE company_id = 1 
GROUP BY month

Sequelize

const sequelize = require('sequelize');
const userCtrl = require('../models/userCtrl')
...
const res = await userCtrl.findAll({
  attributes: [
    [sequelize.fn('to_char', sequelize.col('created_date'), 'YYYY-mm'), 'month'],
    [sequelize.fn('count', sequelize.col('user_id')), 'created_cnt']
  ],
  where: {
    company_id: 1,
  },
  group: ['month'],
});

sequelize.fn...データベース関数を指定
sequelize.col...対象のカラムを指定

蛇足

MySQLではTO_CHAR関数の代わりにDATE_FORMAT関数を使う
指定するフォーマットには、「%」文字をつける

SELECT
DATE_FORMAT(created_date, '%Y-%m') AS month,
COUNT(user_id) AS created_cnt
...

参考

Sequelize公式 - sequelize.fn
MySQL5.6リファレンスマニュアル - DATE_FORMAT

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Sessionを改めて勉強する

Sessionを利用するときはライブラリを使ってばかりで、中身をきちんと理解していなかったのでプレーンなNode.js/TypeScriptを使って勉強してみます。

コード

じゃあ早速Node.jsでコードを書いていきます。

import { IncomingMessage, ServerResponse } from 'http';

const http = require('http')
const session = new Map<string, Map<string, string>>();
let id = 0;

// CookieをMap型に変換する
const getCookies = (req: IncomingMessage): Map<string, string> => {
  if (!req.headers.cookie) return null;

  let cookieMap = new Map<string, string>();
  req.headers.cookie.split(';').forEach(cookie => {
    const data = cookie.split('=');
    cookieMap.set(data[0], data[1]);
  });
  return cookieMap;
};

const app = function(req: IncomingMessage, res: ServerResponse, next: Function) {
  const cookies = getCookies(req);
  let sessionId = (cookies? cookies.get('id') : null);

  if (sessionId) {
    const sessionData = session.get(sessionId);
    console.log('session id:' + id + ', userName:' + sessionData.get('userName'));
  } else {
    id++;
    session.set(String(id), new Map<string, string>().set('userName', 'Taro_' + id));
    res.setHeader('Set-Cookie', 'id=' + id + ';');
  }

  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
};

http.createServer(app).listen(3000);

はい。これだけです。
試してみます。

$ curl -i localhost:3000/
HTTP/1.1 200 OK
Set-Cookie: id=1;
Content-Type: text/plain
Date: Fri, 13 Mar 2020 11:48:51 GMT
Connection: keep-alive
Transfer-Encoding: chunked

Hello World

初回接続時には、セッションが作成され、クッキーにセッションidが返却されます。
Set-Cookie: id=1;の部分です。

$ curl -i -H 'Cookie: id=1' localhost:3000/
HTTP/1.1 200 OK
Content-Type: text/plain
Date: Fri, 13 Mar 2020 11:49:08 GMT
Connection: keep-alive
Transfer-Encoding: chunked

Hello World

# サーバの出力値
session id:1, userName:Taro_1

次に接続する際には、クッキーにセッションidを渡してあげることで、サーバ側でもセッション内のデータを取得・利用することが可能になります。

というのがコードで表現したセッションです。
解説していきます。

解説

Cookieを利用する

HTTPはステートレスです。状態を保持させません。

もし状態を保ちたい時にはCookieを利用します。
Cookieはクライアント側に保持します。

Node.jsでのクッキー返却方法
// Set-CookieをHeaderに付与することでクッキーを返却可能です
res.setHeader('Set-Cookie', 'id=' + id + ';');

クライアント側に保持するので改ざん可能です。そのため、改ざんされたくないような重要な情報はセッションに保存する必要があります。

セッションデータの保持

セッションはセッションIDを発行し、クッキーに保有させることでセッション情報を利用可能になります。

今回セッションIDは連番で作成していますが、セッションIDを推測されてしまうと重要な情報が閲覧されてしまう可能性があるため、ハッシュ値などを利用してランダムな値を発行させます。

セッションは以下のような場所に保存します。

  • メモリ
  • DB
  • KVS
  • ファイル

今回は以下のようにメモリに保存しています。

メモリにセッションを保持
const session = new Map<string, Map<string, string>>();
session.set(String(id), new Map<string, string>().set('userName', 'Taro_' + id));

以上。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

2020年から始めるAzure Cosmos DB - Node.js で CRUD アプリを作る

th.jpeg

この記事について

本記事は、2020年3月6日 (米国時間) にて、Azure Cosmos DB に新しく Free Tier (無償利用枠) が登場したことに伴い、改めて Azure Cosmos DB を色々と触っていく試みの 2 回目です。
今回は、Microsoft Docs のチュートリアルを参考に、Express.js を使って、Azure Cosmos DB に CRUD を行う 簡易な Web アプリケーションの作成および実行を行います。
※ Express.js について知りたい方は、以下の記事を参照してください。

対象読者

  • Azure Cosmos DB について学習したい方
  • Azure Cosmos DB を使ってみたい方
  • Node.js で Azure Cosmos DB への CRUD 操作を行いたい方
  • 鬼滅の刃が好きな方 (笑)

開発環境準備

環境

OS は好きなものを使ってください。今回、筆者は以下の macOS 環境を使用しています。

  • OS: macOS Catalina Version 10.15.3
  • Node.js: v12.16.1

Azure Cosmos DB

前回の記事を参考にして、新しく Azure Cosmos DB を作成します。

Visual Studio Code

インストールがまだの方は、リンクより、インストーラーをダウンロードしてください。

※コードエディタはお好きなものを利用頂いて問題ありませんが、本記事では、一部 Visual Studio Code の拡張機能を利用します。

Visual Studio Code を起動後、拡張機能の画面より Azure Cosmos DB の拡張機能をインストールします。

image01.png

インストールが完了すると、メニューに Azure のアイコンが追加されます。
Azure アイコンを選択すると、[COSMOS DB] タブが表示されるので、[Sign in Azure...] を選択し、Azure にサインインします。

image02.png

サインインに成功すると、前回作成した Azure Cosmos DB アカウント、およびデータベースやコンテナが確認できます。

image03.png

Node.js

公式サイトより、LTS 版のインストーラーをダウンロードし、インストールを行ってください。

開発

データベースの作成

今回の Web アプリケーション用に、新しくデータベースを作成します。
前回記事 と同様に、Azure にログインし、Azure Cosmos DB アカウントの [データ エクスプローラー] 画面を表示します。
[New Container] 右横からメニューを展開し、[New Database] を選択します。

image04.png

[New Database] 画面が表示されますので、以下の内容を入力し、[OK] を選択してデータベースを作成します。

image05.png

  • Database id: DamonSlayer
  • Provision throughput: On
  • Throughput: Manual, 400

データベースが正常に作成され、一覧に [DamonSlayer] データベースが表示されたことを確認します。
[DamonSlayer] データベースの右横にある [・・・] を選択し、メニューより [New Container] を選択します。

image06.png

[Add Container] 画面が表示されますので、以下の内容を入力し、[OK] を選択してコンテナーを作成します。

  • Database id: Use existing, DamonSlayer
  • Container id: Characters
  • Indexing: Automatic
  • Partition Key: /category
  • My partition key is larger than 100 bytes: Off
  • Provision dedicated throughput for this container: Off

image07.png

コンテナーが正常に作成され、一覧に [Characters] コンテナーが表示されたことを確認します。

image08.png

※Visual Studio Code の拡張機能を利用して、新しくデータベースおよびコンテナーを作成することも可能ですが、Throughput が 1000 からしか選択できず、無償枠の範囲を超過してしまうため、ご注意ください。

CRUD アプリの仕様

今回は簡易的なもののため、指定の URL に GET でアクセスした際に、CRUD 処理を行うこととします。
CRUD 処理にて必要となる情報については、クエリパラメータで送信します。
※本来のアプリケーション開発では、非現実的な仕様のため、そのまま流用することは避けてください。ただし、Express.js を使用したアプリケーション開発の経験がある方であれば、POST 送信や JWT を使った認証など、一部コードを書き換えることで本番に近い利用も可能にできるとは思っています。

プロジェクト作成

プロジェクトのルートディレクトリを作成します。
本記事では、 azure-cosmosdb-samples というディレクトリを作成して使用します。

mkdir -p azure-cosmosdb-samples

ルートディレクトリを作成したら、npm initで package.json を作成します。

cd azure-cosmosdb-samples
npm init -y

実行すると、ルートディレクトリ直下に package.json が作成されます。
package.json 内にある main 要素について、index.js から app.js に書き換えます。

package.json
{
  "name": "azure-cosmosdb-samples",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

TypeScript および Express.js のインストール

今回は、Node.js + Express.js + TypeScript で開発を行うため、Express.js と TypeScript をインストールします。

npm install body-parser cookie-parser cors express morgan
npm install --save-dev @types/body-parser @types/cookie-parser @types/cors @types/express @types/node @types/morgan npm-run-all ts-node ts-node-dev typescript

インストールが完了したら、TypeScript のバージョンを確認します。
筆者の環境では、「Version 3.8.3」となっています。

npx tsc -v
実行結果
Version 3.8.3

バージョンが正常に確認できたら、tsconfig.json を作成します。

npx tsc --init

コマンドを実行すると、ルートディレクトリ配下にtsconfig.jsonが作成されます。
tsconfig.json の中には様々な要素が記載されていますが、今回は開発に必要となる以下の要素のみ、設定をします。

tsconfig.json(一部)
{
  "compilerOptions": {
    "target": "ES2019",
    "module": "commonjs",
    "lib": [
      "ES2019",
      "DOM"
    ], 
    "sourceMap": true,
    "outDir": "./dist",
    "strict": true, 
    "typeRoots": [
      "./node_modules/@types"
    ],
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": [
    "src/**/*.ts"
  ],
  "exclude": [
    "node_modules"
  ]
}

tsconfig.json を更新したら、package.json に戻り、scripts 要素を更新します。

package.json(scripts要素部分のみ記載)
{
  "scripts": {
    "dev": "ts-node-dev --respawn src/app.ts",
    "clean": "rimraf dist/*",
    "tsc": "tsc",
    "build": "npm-run-all clean tsc",
    "start": "npm run build && node ./dist/app.js"
  },
}

scripts 内にある dev にて、ts-node-devの指定をしているため、ルートディレクトリ以下に .node-dev.json を作成します。

.node-dev.json
{
  "notify": false
}

@azure/cosmos のインストール

Azure Cosmos DB SQL API 用の JavaScript および Node.js SDK ライブラリをインストールします。
このライブラリを利用する事で、簡単に Azure Cosmos DB へ接続および操作を行うことが可能になります。

npm install @azure/cosmos

コーディング

準備ができたので、実際のコーディングを行っていきます。
ルートディレクトリ以下に、新しくsrcディレクトリを作成します。
TypeScript のコードは、この src ディレクトリ以下に記述していきます。

mkdir -p src

src/class

送信されたリクエストに対するレスポンスのデータ型を定義します。

src/class/resJson.ts
export interface ResJson {
  success: boolean;
  message: string;
  data: any;
}

src/common

(あんまり好きではないですが、よくある共通なんとか〜以外に良いディレクトリを思いつきませんでした。。)
実際にレスポンスを送信するクラスを定義します。

src/common/appRes.ts
import { Response, Request, NextFunction } from 'express';
import { ResJson } from '../class/resJson';

export class AppRes {
  public static sendJson (res: Response, isSuccess: boolean = false, message: string = '' , jsonData: any = null) {
    const obj: ResJson = {
      data: jsonData,
      message: message,
      success: isSuccess
    };
    res.set('Cache-Control', 'no-cache').json(obj);
    return;
  }

  public static sendError (next: NextFunction, message: string, err?: any): void {
    let errors: any = [];
    if (err instanceof Array) {
      err.forEach((e) => {
        errors.push(e);
      })
    } else {
      errors.push(err);
    }
    next({ message: message, data: errors });
    return;
  }
}

src/config

アプリの設定値を定義します。
COSMOSDB_CONFIGの中にて、Azure Cosmos DB への接続に使用する値を定義します。
endpointおよびkeyの部分は、Azure ポータル上で確認できる URI および プライマリ キー の値に置き換えてください。

image09.png

src/config/appConfig.ts
export class AppConfig {
  public static PORT_NUMBER = 3000
  public static MAX_REQUEST_SIZE = 20000000
  public static COSMOSDB_CONFIG = {
    endpoint: "<Your Azure Cosmos account URI>",
    key: "<Your Azure Cosmos account key>",
    databaseId: "DamonSlayer",
    containerId: "Characters",
    partitionKey: { kind: "Hash", paths: ["/category"] }
  }
}

src/controllers

コントローラー部分を定義します。コントローラーの中で @azure/cosmos を利用した CRUD 処理を実装しています。CRUD の各詳細については、次回の記事で説明しようと思います。

src/controllers/cosmosdb.controller.ts
import { CosmosClient, Database, Container } from '@azure/cosmos';
import { NextFunction, Request, Response } from 'express';
import { AppRes } from '../common/appRes';
import { AppConfig } from '../config/appConfig';

export class CosmosDbController {
  private _errors: any;

  public async fetchList(req: Request, res: Response, next: NextFunction) {
    try {
      const { endpoint, key, databaseId, containerId } = AppConfig.COSMOSDB_CONFIG;
      const client: CosmosClient = new CosmosClient({ endpoint, key });
      const database: Database = client.database(databaseId);
      const container: Container = database.container(containerId);

      const querySpec = {
        query: "SELECT * FROM Items"
      };
      const { resources: items } = await container.items
        .query(querySpec)
        .fetchAll();
      console.info("fetch success!");
      AppRes.sendJson(res, true, "fetch success!", items);
    } catch (e) {
      console.error(e.message);
      this._errors.push(e.message);
      AppRes.sendError(next, "fetch error.", this._errors);
    }
  }

  public async fetch(req: Request, res: Response, next: NextFunction) {
    try {
      const { endpoint, key, databaseId, containerId } = AppConfig.COSMOSDB_CONFIG;
      const client: CosmosClient = new CosmosClient({ endpoint, key });
      const database: Database = client.database(databaseId);
      const container: Container = database.container(containerId);

      const querySpec = {
        query: `SELECT * FROM Items WHERE Items.id = "${req.query.id}"`
      };
      const { resources: items } = await container.items
        .query(querySpec)
        .fetchAll();
      console.info("fetch success!")
      if (items.length == 0) {
        AppRes.sendJson(res, true, "No data.", items);
      } else {
        AppRes.sendJson(res, true, "fetch success!", items);
      }
    } catch (e) {
      console.error(e.message);
      this._errors.push(e.message);
      AppRes.sendError(next, "fetch error.", this._errors);
    }
  }

  public async create(req: Request, res: Response, next: NextFunction) {
    try {
      const { endpoint, key, databaseId, containerId } = AppConfig.COSMOSDB_CONFIG;
      const client: CosmosClient = new CosmosClient({ endpoint, key });
      const database: Database = client.database(databaseId);
      const container: Container = database.container(containerId);

      const newItem = {
        id: req.query.id,
        category: req.query.category,
        name: req.query.name,
        description: "",
        isAlive: true
      };
      await container.items.create(newItem);
      AppRes.sendJson(res, true, "create success!", newItem);
    } catch (e) {
      console.error(e.message);
      this._errors.push(e.message);
      AppRes.sendError(next, "create error.", this._errors);
    }
  }

  public async update(req: Request, res: Response, next: NextFunction) {
    try {
      const { endpoint, key, databaseId, containerId } = AppConfig.COSMOSDB_CONFIG;
      const client: CosmosClient = new CosmosClient({ endpoint, key });
      const database: Database = client.database(databaseId);
      const container: Container = database.container(containerId);

      const updateItem = {
        id: req.query.id,
        category: req.query.category,
        name: req.query.name
      };
      await container.item(req.query.id, req.query.category)
        .replace(updateItem);
        AppRes.sendJson(res, true, "update success!", updateItem);
    } catch (e) {
      console.error(e.message);
      this._errors.push(e.message);
      AppRes.sendError(next, "update error.", this._errors);
    }
  }

  public async delete(req: Request, res: Response, next: NextFunction) {
    try {
      const { endpoint, key, databaseId, containerId } = AppConfig.COSMOSDB_CONFIG;
      const client: CosmosClient = new CosmosClient({ endpoint, key });
      const database: Database = client.database(databaseId);
      const container: Container = database.container(containerId);
      await container.item(req.query.id, req.query.category).delete();
      AppRes.sendJson(res, true, `delete item id=${req.query.id} category=${req.query.category}`);
    } catch (e) {
      console.error(e.message);
      this._errors.push(e.message);
      AppRes.sendError(next, "delete error.", this._errors);
    }
  }
}

src/routes

先ほど作成した CosmosDbController クラスに紐づく、ルーティングを行うクラスを定義します。

src/routes/cosmosdbRouter.ts
import { NextFunction, Request, Router, Response } from 'express';
import { CosmosDbController } from '../controllers/cosmosdb.controller';

export class CosmonDbRouter {

  router: Router;
  controller: CosmosDbController;

  constructor () {
    this.router = Router();
    this.controller = new CosmosDbController();
    this.init();
  }

  init () {
    this.router.get('/list', this.controller.fetchList);
    this.router.get('/detail', this.controller.fetch);
    this.router.get('/create', this.controller.create);
    this.router.get('/update', this.controller.update);
    this.router.get('/delete', this.controller.delete);
  }
}

const cosmosdbRouter = new CosmonDbRouter();
cosmosdbRouter.init();

export default cosmosdbRouter.router;

src

アプリの起動時に最初に実行される処理を定義します。
この中で、Express の Web サーバの起動なども行います。

src/app.ts
import bodyParser from 'body-parser';
import cookieParser from 'cookie-parser';
import express from 'express';
import { NextFunction, Request, Response } from 'express';
import logger from 'morgan';
import cors from 'cors';
import { AppRes } from './common/appRes';
import { AppConfig } from './config/appConfig';
import CosmonDbRouter from './routes/cosmosdbRouter';

class App {
  public express: express.Express;

  constructor() {
    this.express = express();
    this.middleware();
    this.routes();
  }

  private middleware(): void {
    this.express.use(cors({
      credentials: true,
      methods: 'GET',
      origin: ['']
    }));
    this.express.use((req: Request, res: Response, next: NextFunction) => {
      console.debug((new Date().toLocaleDateString()) +
        '@@@Request Url' + req.url);
      next();
    })
    this.express.use(bodyParser.json({
      limit: AppConfig.MAX_REQUEST_SIZE
    }));
    this.express.use(cookieParser());
    this.express.use(logger('dev'));
  }

  private routes(): void {
    this.express.use('/api/cosmosdb', CosmonDbRouter);
    this.express.use((req: Request, res: Response, next: NextFunction) => {
      next({ message: `Requested Path is undefined. url=${req.url}` });
    })
    this.express.use((err: any, req: Request, res: Response, next: NextFunction) => {
      if (!res.headersSent) {
        AppRes.sendJson(res, false, err.message, err.data);
      }
    });
  }
}

const port = AppConfig.PORT_NUMBER;
const app = new App();
app.express.listen(port, () => {
  console.info(`Waiting at port ${port}. DateTime=${escape(new Date().toLocaleDateString())}`);
}).on('error', (error) => {
  console.error(`Port ${port} does not open. \r\n${error.message}`);
  process.exit(1);
});

サンプルデータ登録

CRUD アプリを作成しましたが、今のままでは Azure Cosmos DB には 1 つもデータがありません。
そこで、Azure Cosmos DB にテスト用のサンプルデータを登録していきます。

ルートディレクトリ以下に、sample.json ファイルを作成します。

sample.json
[
  {
    "id": "1",
    "category": "main-character",
    "name": "竈門 炭治郎",
    "age": 15,
    "height": 165,
    "description": "妹を救い、家族の仇討ちを目指す、心優しい少年。鬼や相手の急所などの“匂い”を嗅ぎ分けることができる。",
    "isAlive": true
  },
  {
    "id": "2",
    "category": "main-character",
    "name": "竈門 禰?豆子",
    "age": 14,
    "description": "炭治郎の妹。鬼に襲われ、鬼になってしまうが、他の鬼とは違い、人である炭治郎を守るよう動く。",
    "isAlive": true
  },
  {
    "id": "3",
    "category": "enemy",
    "name": "鬼舞辻 無惨",
    "description": "禰?豆子を鬼に変えた者で炭治郎の宿敵。普段は人間のふりをして暮らしている。",
    "isAlive": true
  },
  {
    "id": "4",
    "category": "friend",
    "name": "煉獄 杏寿郎",
    "age": 20,
    "description": "鬼殺隊の“柱”の一人。“炎の呼吸”で鬼を殲滅する。",
    "isAlive": false
  }
]

冒頭にインストールした Visual Studio Code の拡張機能 [Azure Cosmos DB]では、json ファイルを使ってデータをインポートさせることができます。

image10.png

[DamonSlayer] -> [Characters] を右クリック -> [Import Document into a Collection...] を選択し、sample.json 選択してデータをインポートします。

実行

ルートディレクトリに移動し、npm startで作成した CRUD アプリを起動します。

cd azure-cosmosdb-sample
npm start

コマンドを実行することで、distディレクトリが新しく作成され、TypeScript から JavaScript にコンパイルされたソースコードが出力されます。CRUD アプリはこの出力された JavaScript を使って動いています。
以下のような実行結果が出力されれば、正常に起動ができています。

実行結果(例)
Waiting at port 3000. DateTime=2020-3-14

一覧データ取得

Webブラウザを起動し、以下の URL にアクセスします。

http://localhost:3000/api/cosmosdb/list

先ほど登録したデータの一覧が取得され、画面に表示されます。

image11.png

ID に紐づくデータの取得

指定した id に一致するデータのみ取得する場合は、以下の URL にアクセスします。
URL のクエリパラメータ(? マーク以降の文字列)内で、任意のid値を入力して下さい。
(今回は、id が "3" である 鬼舞辻 無惨 のデータを取得します。)

http://localhost:3000/api/cosmosdb/detail?id=3

image12.png

データの登録

新しくデータを登録する場合は、以下の URL にアクセスします。
クエリパラメータ内にて指定した id、category、name の値を使ってデータを登録することができます。
(今回は、id を "5" として 鱗滝 左近次 のデータを登録します。)

http://localhost:3000/api/cosmosdb/create?id=5&category=friend&name=鱗滝%20左近次

※URL エンコード版
http://localhost:3000/api/cosmosdb/create?id=5&category=friend&name=%E9%B1%97%E6%BB%9D%20%E5%B7%A6%E8%BF%91%E6%AC%A1

データの更新

既存のデータを更新する場合は、以下の URL にアクセスします。
クエリパラメータ内にて指定した id と category に紐づくデータの name 値を、同じくクエリパラメータ内にて指定した name の値に書き換えます。
(今回は、id を "5" として name 値を 鱗滝 左近次 から 冨岡 義勇 に更新します。)

http://localhost:3000/api/cosmosdb/update?id=5&category=friend&name=冨岡%20義勇

※URL エンコード版
http://localhost:3000/api/cosmosdb/update?id=5&category=friend&name=%E5%86%A8%E5%B2%A1%20%E7%BE%A9%E5%8B%87

データの削除

既存のデータを削除する場合は、以下の URL にアクセスします。
クエリパラメータ内にて指定した id と category に紐づくデータを削除します。
(今回は、id を "5" 、 category が "friend" のデータ 冨岡 義勇 を削除します。)

http://localhost:3000/api/cosmosdb/delete?id=5&category=friend

さいごに

今回は、Node.js + Express.js + TypeScript を使って、Azure Cosmos DB への簡易的な CRUD アプリを作成しました。
しかしながら、このアプリは全てのリクエストが GETで行われており、実際の本番環境には使えるものではありません
ただし、この CRUD アプリに多少手を加えることで、簡単に POST で同じ通信を行ったり、認証された状態でしか CRUD を実行できないように、動作を変更させることは可能になります。

実際に、これを読んだあなたの手で、その処理を実装してみてください。
また今回のソースコードの中には、一部無駄なコードの書き方をしている部分があります。もっと簡略化できるポイントがないか、探してみてください。そして、見つけたら直してみてください。

今回のソースコードは GitHub にて公開しています。是非 Pull Request してみてください。

関連リンク

前回記事

GitHub

その他

参考情報

Microsoft Docs

npm

Hatena Blog

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む