ファイルへのデータの書き出し
たとえばウェブアプリケーションがログを取る必要などがある場合、最も簡素な方法はテキストファイルに書き出すことです。Node.jsにはじめから組み込まれているfsというファイルシステムモジュールはとても使いやすいです。
const fs = require('fs')
const fileName = 'file.txt'
//check whether file exists or not
if(fs.existsSync(fileName)){
const data = new Date().toString() + " log added\n"
//fs.appendFile adds new text asynchronously
fs.appendFile(fileName, data, (err) => {
if(err){
console.log(err)
} else {
console.log("write successful")
}
})
} else {
const data = new Date().toString() + " the first log\n"
//fs.writeFile writes data and also this creates file if it doesn't exist
fs.writeFile(fileName, data, (err) => {
if(err){
console.log(err)
} else {
console.log("file create successful")
}
})
}
このコードを走らせるとfile.txtファイルが作成されそのなかにログが記入されたのが確認されます。そして再度走らせるたびに新しいログが追記されます。
ファイルへのデータの読み取り
今度はファイルを読み込んでみましょう。この場合fs.readFileを用います。
const fileName = 'file.txt'
fs.readFile(fileName, 'utf-8', (err, data) => {
if(err){
console.log(err)
} else {
console.log(data)
}
})
応用編 ~morganでログをつけましょう~
開発においても、運用においてもログをつけることは煩瑣でありながら何よりも大事な作業です。morganはログをつけるための非常に便利なミドルウェアで、どのようなウェブアプリでも欠かせません。この応用ではmorganを使ってコンソールとログファイルの両方にログをつけていきましょう。
まずmorganをインストールして、ディレクトリとログファイルを作成しましょう。
npm install morgan
mkdir logs
cd logs
type server.log > server.log
次にログをつけるコードを書いていきましょう。
const fs = require('fs')
const morgan = require('morgan')
const path = require('path')
const express = require('express')
const server = express()
const port = 3000
const filePath = path.join(__dirname, 'logs', 'server.log')
// morganはログの種類の定義を求めてきます。
// ここでは一般的なログをファイルに記入して
// 簡素な開発用ログをコマンドラインに書きましょう
server.use(morgan('common', {
stream: fs.createWriteStream(filePath, {flags:"a"})
}))
server.use(morgan('dev'))
server.get('/', (req, res) => {
res.send('Hello World!')
})
server.listen(port, () => {
console.log('server listening on:' + port)
})
これでローカルホスト3000にgetリクエストがあるたびにその記録が記入されるようになりました。
データベースの利用
ウェブアプリケーションが日々追加、削除、更新される情報を大量に扱うならデータベースの導入は欠かせないでしょう。
Mongo DB
データベースには色々ありますが、ここはJavaScriptと親和性が高いMongoDBを使っていきましょう。
まずはMongoDBのGUIとShellをインストールしましょう。
ローカル環境でのDBの作成
MongoDB Shellでデータベースとコレクションを作成します
use testDB
db.createCollection("users")
無事作成されたか確認してみましょう
MongoDB Compassで
mongodb://127.0.0.1:27017/testDB
usersという空のコレクションが確認できれば良いです。
次にmongoose というMongoDBを操作するためのモジュールをインストールしましょう
mongoose
npm install mongoose
次にコードを書いていきましょう。コード内のコメントでmongooseの使い方を説明します。
コードとしてjadeを用いたフォームから受け取った値でドキュメントを作成するものです。
const express = require('express')
const mongoose = require('mongoose')
const bodyParser = require('body-parser')
const server = express()
const port = 3000
// データベースのパス
const dbPath = "mongodb://127.0.0.1:27017/testDB"
// 接続する関数(非同期)
mongoose.connect(dbPath, (err) => {
if(!err){
console.log("connected to database")
} else {
throw err
}
})
// スキーマの宣言
// スキーマとは厳密なデータ定義がないMongoDBのデータを検索したり作成するための図面
const Schema = mongoose.Schema
// スキーマの定義はプロパティの名前とデータ型で行います
// また値が有効かどうかの検証を行うひつようがあり
// そのための関数をスキーマ内で定義しておきましょう
const validateLength = value => {
return value && value.length
}
const validateNumber = value => {
return value && parseInt(value)
}
const userSchema = new Schema({
firstName:{
type:String,
validate:[validateLength, 'first name is required']
},
lastName:{
type:String,
validate:[validateLength, 'last name is required']
},
age:{
type:Number,
validate:[validateNumber, 'Not a valid number']
},
})
// スキーマからモデルを定義します。
// モデルから検索や新しいドキュメントの作成などができる。
const userModel = mongoose.model('users', userSchema)
server.set('view engine', 'jade')
server.use(bodyParser.urlencoded({extended:true}))
server.use(bodyParser.json())
server.get('/', (req, res) => {
res.render('index')
})
server.post('/addUser', (req, res) => {
// ドキュメントの作成
userModel.create(req.body.user).then(result => {
res.render('postResult', {message:'post successful'})
}).catch(reason => {
if(reason){
res.render('postResult', {message:'post failed'})
}
})
})
server.listen(port, () => {
console.log('server listening on:' + port)
})
フォーム送信用のjadeファイル
doctype html
html
head
title Jade Example
body
h1 Add User
form(method='post', action='/addUser')
fieldset
legend add user
label first name
input(type="text" name='user[firstName]')
label last name
input(type='text' name='user[lastName]')
label age
input(type='number' name='user[age]')
input(type='submit' value='Save')
作成の成否確認のためのjadeファイル
doctype html
html
head
title #{message}
body
h1 #{message}
ドキュメントの変更と削除
ついでにドキュメントの変更と削除もやってみましょう。まずはindex.jadeファイルを変更しましょう。
doctype html
html
head
title Jade Example
body
h1 Add User
form(method='post', action='/addUser')
fieldset
legend add user
div
label first name
input(type="text" name='user[firstName]')
div
label last name
input(type='text' name='user[lastName]')
div
label age
input(type='number' name='user[age]')
div
input(type='submit' value='Save')
h1 Users
- if(docs.length)
ol
each user in docs
li #{user.firstName} #{user.lastName} #{user.age}
form(method='post' action="/deleteUser/#{user._id}?_method=DELETE")
input(name='_method' value='DELETE' type="hidden")
input(type='submit' value="delete")
a(href="/editUser/#{user._id}") edit
次に新しく変更用の入力画面としてeditUser.jadeファイルを作成していきます。
doctype html
html
head
title Jade Example
body
h1 Add User
form(method='post', action='/addUser')
fieldset
legend add user
div
label first name
input(type="text" name='user[firstName]')
div
label last name
input(type='text' name='user[lastName]')
div
label age
input(type='number' name='user[age]')
div
input(type='submit' value='Save')
h1 Users
- if(docs.length)
ol
each user in docs
li #{user.firstName} #{user.lastName} #{user.age}
form(method='post' action="/deleteUser/#{user._id}?_method=DELETE")
input(name='_method' value='DELETE' type="hidden")
input(type='submit' value="delete")
a(href="/editUser/#{user._id}") edit
そしてserver.jsに変更を加えましょう。
const express = require('express')
const mongoose = require('mongoose')
const bodyParser = require('body-parser')
const server = express()
const port = 3000
const dbPath = "mongodb://127.0.0.1:27017/testDB"
mongoose.connect(dbPath, (err) => {
if(!err){
console.log("connected to database")
} else {
throw err
}
})
const Schema = mongoose.Schema
const validateLength = value => {
return value && value.length
}
const validateNumber = value => {
return value && parseInt(value)
}
const userSchema = new Schema({
firstName:{
type:String,
validate:[validateLength, 'first name is required']
},
lastName:{
type:String,
validate:[validateLength, 'last name is required']
},
age:{
type:Number,
validate:[validateNumber, 'Not a valid number']
},
})
const userModel = mongoose.model('users', userSchema)
server.set('view engine', 'jade')
server.use(bodyParser.urlencoded({extended:true}))
server.use(bodyParser.json())
server.get('/', async (req, res) => {
await userModel.find().exec().then(docs => {
res.render('index', {docs:docs})
})
})
server.post('/addUser', (req, res) => {
userModel.create(req.body.user).then(result => {
res.redirect('/')
}).catch(reason => {
if(reason){
res.render('postResult', {message:reason})
}
})
})
// editUser.jadeへユーザー情報を送ります
server.get('/editUser/:id', (req, res) => {
// findByIdはドキュメントをユニークIDで探します
userModel.findById(req.params.id).exec().then(doc => {
res.render('editUser', {user:doc})
}).catch(reason => {
if(reason){
res.render('postResult', {message:'search failed'})
}
})
})
// 実際のドキュメント変更
server.post('/editUser/:id', (req, res) => {
console.log(req.body)
// findByIdAndUpdateはユニークIDでドキュメントを発見し渡された値に更新します
userModel.findByIdAndUpdate(req.params.id, req.body.user).then(
res.redirect('/')
).catch(reason => {
if(reason){
res.render('postResult', {message:reason})
}
})
})
// ドキュメント削除用
server.post('/deleteUser/:id', (req, res) => {
// findByIdAndDelete はユニークIDでドキュメントを探しそれを削除します
userModel.findByIdAndDelete(req.params.id).then(
res.redirect('/')
).catch(reason => {
if(reason){
res.render('postResult', {message:'post failed'})
}
})
})
server.listen(port, () => {
console.log('server listening on:' + port)
})
環境変数の設定と参照
最後に環境変数についてです。
たとえばウェブアプリが外部APIを用いる場合APIキーが必要になりますし、mongoDBをクラウドで扱う場合などではユーザー名とパスワードをパスに用いなければならず、それらを主要なプログラムにハードコードするのはとても危険です。
ぜひとも環境変数に組み込みましょう。
SET MONGODB_USERNAME [YOUR_USER_NAME]
一度設定した環境変数は以下の記法で参照できます。
const mongoUserName = process.env.MONGODB_USERNAME
次回へ
その4へ続きます。
次はテストについてです。