Node.js で Express 製の REST API を実装するメモ。

Bookというモデルの CRUD 用の 単純な API を実装する。

開発用の実行環境の構築

環境は Docker, docker-compose を使う。それぞれセットアップが完了していること。

プロジェクトのルートを用意。 アプリのソースはsrcにいれる。

$ mkdir myapi
$ cd myapi
$ mkdir src
$ touch Dockerfile
$ touch docker-compose.yml

Dockerfile

FROM node:11

WORKDIR /home/node
RUN apt-get -y update\
  && npm install -g express\
  && npm install -g express-generator
UESR node
  • Dockerfile は、Node をベースにしたものを使う。
  • apt-get updateでパッケージは更新しておく。
  • expressexpress-generatorは root じゃないと入れられないので入れておく。
  • CMD はまだ指定しない

docker-compose.yml

version: "3"
services:
  web:
    build:
      context: .
    environment:
      - TZ=Asia/Tokyo
      - http_proxy=${http_proxy}
      - https_proxy=${https_proxy}
    ports:
      - 3000:3000
    depends_on:
      - mongodb
    volumes:
      - ./src:/home/node
    command: bash
    tty: true

  mongodb:
    image: mongo:4.2.8
    volumes:
      - mongodata:/data/db

volumes:
  mongodata:
  • command と tty を指定してコンテナが終了しないようにする。

そして build。proxy が必要な場合は --build-args http_proxy=http://proxy:8080 --build-args https_proxy=http://proxy:8080 をオプション追加する

$ docker-compose build
$ docker-compose up -d
$ docker-compose exec web bash
  1. DockerImage ビルド
  2. コンテナ起動
  3. node のコンテナ接続

Express のインストール

ここからはコンテナ内での作業。

$ express
$ npm install
$ npm start
  1. express のプロジェクトのひな型を生成し、
  2. express のデフォルトの依存モジュールをインストール
  3. express アプリ を起動

express の web アプリが起動したので、http://localhost:3000 にアクセスできるか確認する。

REST API の実装

ひな形から不要なものを削除。public,viewsroutes/user.jsは削除

ORM ライブラリはmongooseを使う。

$ npm install mongoose

app.js の修正

最初に自動生成された app.js は以下のようにする。MongoDB の接続 URI は環境変数MONGO_URIに指定する

var createError = require("http-errors");
var express = require("express");
var path = require("path");
var cookieParser = require("cookie-parser");
var logger = require("morgan");

var indexRouter = require("./routes/index");

var app = express();

// mongodb接続
const mongoose = require("mongoose");
mongoose.connect(process.env.MONGO_URI).catch((e) => {
  console.log(e);
});

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")));

app.use("/", indexRouter);

// catch 404 and forward to error handler
app.use(function (req, res, next) {
  next(createError(404));
});

// 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.send("Internal Server Error"); // WebAPIアプリケーションなのでsendにする。
});

module.exports = app;

Book の model

/models/book.jsを用意する。

let mongoose = require("mongoose");
let Schema = mongoose.Schema;

//book schema definition
let BookSchema = new Schema(
  {
    title: { type: String, required: true },
    author: { type: String, required: true },
    year: { type: Number, required: true },
    pages: { type: Number, required: true, min: 1 },
  },
  {
    timestamps: true,
    versionKey: false,
  }
);

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

Book の Route

/routes/index.jsを編集

var express = require("express");
var router = express.Router();
const bookRouter = require("./book");

router.use("/books", bookRouter);
// リソースが増える場合に追加していけばよい
// router.user('/stores', storeRouter)

module.exports = router;

一覧 GET /books/

Book の一覧を返す

const express = require("express");
const router = express.Router();
const Book = require("../models/book");

/**
 * GET /books/
 * 一覧
 */
router.get("/", async (req, res, next) => {
  try {
    const books = await Book.find({});
    res.status(200).json(books);
  } catch (e) {
    next(e);
  }
});

module.exports = router;

以降module.exports = router;をファイルの末尾に記述したままで、各 router を追記してく。

登録 POST /books/

/**
 * POST /books/
 * 登録
 */
router.post("/", async (req, res, next) => {
  try {
    let book = new Book(req.body);
    // validation
    let invalid = book.validateSync();
    if (invalid) {
      console.log(invalid);
      res.status(400).json({ error: invalid.message });
      return;
    }
    await book.save();
    res.status(200).json(book);
  } catch (e) {
    next(e);
  }
});

詳細 GET /books/:id

/**
 * GET /books/:id
 * 詳細
 */
router.get("/:id", async (req, res, next) => {
  try {
    const book = await Book.findById(req.params.id);
    if (!book) {
      res.status(404).json({ error: "Not Found." });
      return;
    }
    res.status(200).json(book);
  } catch (e) {
    next(e);
  }
});

更新 PATCH /books/:id

/**
 * PATCH /books/:id
 * 更新
 */
router.patch("/:id", async (req, res, next) => {
  try {
    const book = await Book.findById(req.params.id);
    if (!book) {
      res.status(404).json({ error: "Not Found." });
      return;
    }
    // フィールドの更新
    for (field of ["title", "author", "year", "pages"]) {
      if (field in req.body) book[field] = req.body[field];
    }
    // Validate
    let invalid = book.validateSync();
    if (invalid) {
      console.error(invalid);
      res.status(400).json({ error: invalid.message });
      return;
    }
    // save
    await book.save();
    res.status(200).json(book);
  } catch (e) {
    next(e);
  }
});

削除 DELETE /books/:id

/**
 * DELETE /books/:id
 */
router.delete("/:id", async (req, res, next) => {
  try {
    const book = await Book.findById(req.params.id);
    if (!book) {
      res.status(404).json({ error: "Not Found." });
      return;
    }
    await book.remove();
    res.status(204).send();
  } catch (e) {
    next(e);
  }
});

不十分なもの

  • ユニットテスト
  • 細かいバリデーション
  • ロギング
  • 認証

ユニットテストをmocha+chai+sinonで実装する

GET /books/:id の :id は ObjectId に準拠してない場合に例外になるので、事前に検証し 404 を返すなど処理が必要

デバッグログを console.log で出力してるので log4js などの logger の機能が必要。

ほとんどの環境は、認証が必要なので、API キーや barer トークンなどで認証する機能が必要

Udemy 独学でのアプリ開発に限界を感じたら

プログラミング初学者の皆さんに、 Udemy を強くお勧めしたいと思います。 Udemy は世界中のトップレベルのプログラミング講師が提供するオンライン講座を取り揃えています。以下は、 Udemy で学ぶことのメリットについての詳細です。

1. Udemy の豊富なコースの選択肢

Udemyには、数千ものコースがあります。初心者から上級者まで、プログラミングのあらゆるレベルを網羅しています。また、様々なプログラミング言語やツールに関するコースも多数あり、希望に合わせたコースを選ぶことができます。

2. 実践的な学習方法

Udemyのコースは、理論だけでなく実践的な学習も行えます。多くのコースには、プログラムの作成や実際のプロジェクトに取り組む演習が含まれています。これにより、理論だけでなく実践的なスキルも身につけることができます。

3. Udemy には質の高い講師陣

Udemyの講師陣には、世界中のトップレベルのプログラマーが多数在籍しています。彼らは、実務での経験を活かして、分かりやすい講義を行っています。

4. 初学者が始めるのにとても手頃な価格

Udemyのコースは、他のオンライン講座と比べて手頃な価格で提供されています。また、一度購入すると、終身アクセスが得られるので、自分のペースで学習することができます。

以上の理由から、プログラミング初学者の方には、Udemyが最適な学習プラットフォームであると考えられます。ぜひ一度、Udemyのコースを体験してみてください。


ウェブ開発の人気オンラインコース


ITとソフトウェアの人気オンラインコース


デザインの人気オンラインコース