「JavaScriptでのWeb開発Node.js Express + MongoDB + ReactでWebアプリを開発しよう〜 その1 〜」の感想・備忘録

スポンサーリンク

kindle本「JavaScriptでのWeb開発Node.js Express + MongoDB + ReactでWebアプリを開発しよう〜 その1 〜」のまとめ。

点数

63点

感想

あまり良い内容ではなかった。
雑な説明が多く、特にPassportの説明は不明な点が多かった。
MongoDbに触れることができた点はよかった。

Expressのインストール

  1. npm init
  2. npm install express --save-dev
    ※entry pointはapp.jsとする
  3. touch app.js
  4. node app.jsで実行
"use strict";

const http = require('http');
const express = require('express');

const app = express()

app.use((req, res, next) => {
  res.send('hello');
});
var server = http.createServer(app);
server.listen('3000');

pug

pugとは

Railsでお馴染みのHamlに似たテンプレートエンジン。
かつてはjadeという名前だった。
ejsやectと比べて圧倒的に記述量を減らすことができる。

pugのインストール

npm install pug --save-dev

app.jsへの追記

const path = require('path');
// 〜省略〜
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.get('/', (req, res, next) => {
 res.render('index', {title: 'Hello World'});
});

views/index.pugの作成

doctype html
html(lang="ja")
  head
    meta(charset="utf-8")
  body
    h1 #{title}

MongoDB

MongoDBとは

  • NoSQLと呼ばれる新しいタイプのデータベースで、RDBMSのように事前に構造を定義する必要がない。
    (ただし、通常は型や最大値・最小値を定義する)
  • BSONと呼ばれる独自のデータ形式で保持する。
  • BSONはJSONのバイナリ版のようなもの(実運用上はほぼ同じ)であり、JavaScriptオブジェクトをそのまま保存することができる。
  • MySQLなどに比べて大量のアクセスに耐えられる。

MongoDBのインストール

  1. Macの場合
    brew tap mongodb/brewの後にbrew install mongodb-community
    brew install mongodbではインストールできなくなったhttps://qiita.com/kazuki5555/items/b80f1f313137dffbb351
    https://github.com/mongodb/homebrew-brew

    Linuxの場合
    yumにmongoDB用の設定を追加してからsudo yum install mongodb-org
    https://qiita.com/daikiojm/items/a3953a56d6328e59a4e7
  2. データ格納用ディレクトリを作成
    mkdir db
  3. 実行
    mongod --dbpath db
    ※コマンドはmondoがクライアント、mongodがサーバ

mongoコマンドの使い方

  1. mongo
  2. use データベース名でデータベースの作成・切り替え
    例)use chatapp
  3. db.コレクション名.insert({xxx: yyy})で挿入
    例)db.messages.insert({username: "山田 太郎", message: "Hello"})
    ※コレクションが存在しない場合は作成される
  4. db.コレクション名.find()で取得

MongoDBには最低1つのデータベースを定義し、その中に最低1つのコレクションを格納する。
例)chatappデータベースにusers, messagesコレクションを作成する。

mongoose

mongooseとは

node.js上でmongoDBを扱うためのライブラリ。
コレクション毎にスキーマを定義しなければならない。

mongooseの使い方

  1. インストール
    npm install mongoose --save-dev
  2. app.jsに接続処理を追記
const mongoose = require('mongoose');
// 〜省略〜
mongoose.connect(
  'mongodb://localhost:27017/chatapp',
  { useNewUrlParser: true, useUnifiedTopology: true },
  err => {
    if (err){
      console.error(err);
    } else{
      console.log("successfully connected to MongoDB.");
    }
  }
);
  1. mkdir schema & touch chema/Message.jsでスキーマファイルを生成
const mongoose = require('mongoose');

const Message = mongoose.Schema({
  username: String,
  message: String,
  date: {type: Date, default: new Date()} // dateに現在日時が登録される
});

module.exports = mongoose.model('Message', Message)
  1. app.jsに登録処理を追記
const Message = require('./schema/Message');
// 〜省略〜
const newMessage = new Message({
  username: req.body.username,
  message: req.body.message
});
newMessage.save((err)=>{
  if (err) {
    throw err;
  }
  console.log("successfully inserted to MongoDB.");
});

登録フォームをpugで作成

  1. views/update.pugを作成
doctype html
html(lang="ja")
  head
    meta(charset="utf-8")
  body
    h1 メッセージを保存
    form(action="update" method="POST")
      input(type="text" name="username" placeholder="名前")
      textarea(placeholder="メッセージ" name="message")
      button(type="submit") 送信
  1. app.js (body-parserはexpressと一緒にインストールされるので、個別のインストールは不要)
const bodyParser = require('body-parser'); // POSTをreq.bodyに格納する
// 〜省略〜
app.use(bodyParser.urlencoded({ extended: false }))
app.get('/update', (req, res, next) => {
  res.render('update');
});
app.post('/update', (req, res, next) => {
  const newMessage = new Message({
    username: req.body.username,
    message: req.body.message
  });
  newMessage.save((err) => {
    if (err) {
      throw err;
    }
    res.redirect('/');
  });
});

データ表示画面をpugで作成

  1. views/index.pugを作成
doctype html
html(lang="ja")
  head
    meta(charset="utf-8")
  body
    h1 投稿一覧
    section
      each msg in messages
        div
          h2 #{msg.username}
          time #{msg.date}
          p #{msg.message}
  1. app.js
Message.find({}, (err, msgs) => {
  if (err) {
    throw err;
  }
  res.render('index', {messages: msgs});
});

express-fileupload

type="file"のinput要素で送信されたデータはbody-parserではパースできないため、express-fileuploadを使う。

  1. npm install express-fileupload --save-dev
  1. app.js
const fileUpload = require('express-fileupload');
// 〜省略〜
app.use(fileUpload());
app.post("/update", (req, res, next) => {
  if(req.files && req.files.image) {
    req.files.image.mv(`./images/${req.files.image.name}`, err => {
      if (err) {
        throw err;
      }
    });
  }
});
  1. update.pug
form(action="update" method="POST" encType="multipart/form-data")
      input(type="text" name="username" placeholder="名前")
      textarea(placeholder="メッセージ" name="message")
      input(type="file" name="image")
      button(type="submit") 送信

アップロードした画像を表示する

app.use(express.static(ディレクトリ名));でディレクトリを公開することできる。

  1. app.js
app.use("/images", express.static(path.join(__dirname, 'images')));
// またはapp.use(express.static('./'));
// 〜省略〜
const newMessage = new Message({
  username: req.body.username,
  message: req.body.message,
  image_path: `/images/${req.files.image.name}`
});
  1. schema/Message.jsにパス保存用のimage_pathを追加
const Message = mongoose.Schema({
  username: String,
  message: String,
  date: {type: Date, default: new Date()},
  image_path: String
});
  1. index.pug
doctype html
html(lang="ja")
  head
    meta(charset="utf-8")
  body
    h1 投稿一覧
    section
      each msg in messages
        div
          h2 #{msg.username}
          time #{msg.date}
          p #{msg.message}
        if msg.image_path
          img(src=msg.image_path)

Passport

Express用の認証ミドルウェア。
ローカル認証やOAuth認証用のモジュールをインストールして使う。
Passportはセッションを使ってユーザー認証を行っている。

Passportのインストール

npm install passport passport-local express-session --save-dev

app.js

const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const session = require('express-session');
// 〜省略〜
app.use(session({ secret: 'HogeFuga', resave: false, saveUninitialized: false, }));
app.use(passport.initialize());
app.use(passport.session());
// 〜省略〜
app.post('/login', passport.authenticate('local', {
  successRedirect: '/',
  failureRedirect: '/login'
}));
// セッション用のシリアライズ(これがないと動作しない)
passport.serializeUser(function(user, done) {
  done(null, user);
});
passport.deserializeUser(function(user, done) {
  done(null, user);
});
// ログインしていない場合の処理
passport.use(new LocalStrategy({
  usernameField: 'username',
  passwordField: 'password'
}, function (username, password, done) {
  process.nextTick(function () {
    if (username === "test" && password === "test") {
      return done(null, username)
    } else {
      console.log("login error")
      return done(null, false, { message: 'パスワードが正しくありません。' })
    }
  })
}));
  • new LocalStrategy()passport.authenticate('local')でセッションが存在しない場合に処理が実行される。
  • 引数のusername, passwordにはルーティング/loginのPOSTパラメータが自動的にセットされる。
  • doneの第1引数にエラーの有無、第2引数にセッションに保存するデータ、をセットする

コメント