Mongose | CRUD RESTful API Endpoints

Photo by Shane on Unsplash

What Is An API?

  • Application Programming Interface

What Is REST?

  • Representational State Transfer

HTTP Methods

  • GET : Retrieve data from a specified resource

Endpoints

The URI/URL where api/service can be accessed by client application

進入 CRUD RESTful API Endpoints 之前,先搞定前置作業

  1. Server 連線基礎設定 ( 安裝 Express )

index.js 設定

const express = require('express')const app = express()
const port = process.env.PORT || 3000
app.post('/users', (req, res) => {
res.send('testing')
})
app.listen(port, () => {
console.log(`Server is up on port ${port}`)
})

mongoose.js 設定請參考 Mongose | Data Validation and Sanitization

2. Package 設定

安裝 nodemon 到開發環境。

npm install --save-dev nodemon

package.json 加入”start” & “dev”

"scripts": {
"start": "node src/index.js",
"dev": "nodemon src/index.js"
},

3 運用 Postman 進行測試

(1) 運用+ New Collection 創立 Task App 接著按下add Request 命名為 Create User

(2) 方法選擇POST 並輸入路由,接著我們想模擬前端送 JSON Request,選擇body / raw / JSON

(3) Send 得到回應

Resource Creation Endpoints

1 設置後端讀取前端 JSON (補充閱讀 : express.json vs bodyParser.json )

app.use(express.json())app.post('/users', (req, res) => {
console.log(req.body)
res.send('testing')
})

2 隨著 code 增加,我們把原本寫在 mongoose.js 裡面的 model 獨立拆出 user.js

3 user.js 設置, require & module.exports

const mongoose = require('mongoose')
const validator = require('validator')
const User = mongoose.model('User', {
name: {
type: String,
required: true,
trim: true
},
age: {
type: Number,
default: 0,
validate(value) {
if (value < 0) {
throw new Error('Age must be a postive number')
}
}
},
email: {
type: String,
required: true,
trim: true,
lowercase: true,
validate(value) {
if (!validator.isEmail(value)) {
throw new Error('Email is invalid')
}
}
},
password: {
type: String,
required: true,
trim: true,
minLength: [7, 'The password is too short, please set more than six characters'],
validate(value) {
if (validator.contains(value, 'password',{ ignoreCase: true})) {
throw new Error('Password cannot contain "password"')
}
}
}
})
const whoami = new User({
name: " Ken Chen ",
email: "KENCHEN@examplemail.com",
password: "pasSwOrD "
})
whoami.save().then(() => {
console.log(whoami)
}).catch((error) => {
console.log('Error!', error)
})
module.exports = User;

4 mongoose.js 移除 const validator = require(‘validator’)

5 index.js require mongoose.js & user.js 與資料庫做連接

require('./db/mongoose')
const User = require('./models/user')

6 資料存入資料庫,並對於 error 設置 status 400 (補充閱讀: httpstatus)

app.post('/users', (req, res) => {
const user = new User(req.body)
user.save()
.then(() => {
res.send(user)
})
.catch((error) => {
res.status(400).send(error)
})
})

7 再次運用 Postman 進行測試,結果符合預期,完成了第一次運用 RESTful API 對資料庫進行操作。

(1) 資料成功存入資料庫

(2) 密碼過短,出現 error 提示 & Status : 400

Resource Reading Endpoints

1 找所有 users 資料

app.get('/users', (req, res) => {
User.find({})
.then((users) => {
res.send(users)
})
.catch((error) => {
res.status(500).send(error)
})
})

2 Postman測試符合預期

3 設置動態路由,路由寫法加上:id,id可以替換成其他字

app.get('/users/:id', (req, res) => {
console.log(req.params);
})

4 結合 findById,成功以id讀取到單筆資料

app.get('/users/:id', (req, res) => {
const _id = req.params.id
User.findById(_id)
.then((user) => {
if(!user) {
return res.status(404).send()
}

res.send(user)
})
.catch((error) => {
res.status(500).send()
})
})

Resource Updating Endpoints

findByIdAndUpdate 第一個參數是 endpoint 所輸入的 id,第二個參數是 req 所修改的資料,第三個參數 new 讓資料更新之後回傳新值、runValidators 使更新的資料會如同建立時 model 的驗證。

app.patch('/users/:id', async (req, res) => {
try {
const user = await User.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true })

if (!user) {
return res.status(404).send()
}
res.send(user)
} catch (e) {
res.status(400).send(e)
}
})

(1) 更新 name 成功,符合預期。

(2) 輸入不存在的ID,出現404,符合預期。

(3) 輸入明顯錯誤的值 (ex. “name”: “”),出現400,符合預期。

(4) 輸入沒有定義的內容,例如身高,會被 mongoose 忽略,顯示狀態碼 200 資料卻沒有符合預期。

(5) 把 req.body 轉換成 array

const updates = Object.keys(req.body)
const allowedUpdates = ['name', 'email', 'password', 'age']
const isValidOperation = updates.every((update) => allowedUpdates.includes(update))
if (!isValidOperation) {
return res.status(400).send({ error: 'Invalid updates!' })
}
  • every() 可以檢查所有的陣列是否全部符合條件 true 否則 false

最終完成這項卡關機制。

Resource Deleting Endpoints

app.delete('/users/:id', async (req, res) => {
try {
const user = await User.findByIdAndDelete(req.params.id)
if (!user) {
return res.status(404).send()
}
res.send(user)
} catch (e) {
res.status(500).send()
}
})

延伸閱讀 :

資管人,曾在半導體業打滾了幾年,持續追逐著那個屬於我的理想形狀。