一個簡單的Koa電影評分系統
阿新 • • 發佈:2022-03-25
基本需求
這個文章想用Koa寫一個比較簡單的、具有基本CRUD功能的電影評分系統。大概提供幾個介面:返回所有電影資訊、電影資訊詳情、修改電影詳情和刪除某電影詳情的功能。
建立一個基本服務
上一篇文章講了,Koa基本就是對Node.js的http包做了一下包裝,讓建立服務這件事比較方便了。但對一些像路由、解析POST請求等需求還是需要一些額外的工具的。先來建立一個新專案:
mkdir movie-api && cd movie-api
npm init -y
npm i koa @koa/router koa-bodyparser mysql2 -S
新建app.js
const Koa = require('koa') const Router = require('@koa/router') const router = new Router() const bodyParser = require('koa-bodyparser') const app = new Koa() router.get('/', ctx => { ctx.body = 'server ok' }) app.use(bodyParser()) .use(router.routes()) .listen(3000, () => console.log('server is running at 3000'))
執行一下這個檔案,就得到了一個基本的Koa服務。
加上資料庫
這次要用從真的資料庫裡取資料返給請求處,所以建立一個數據庫movie_db
,新增一些資料:
INSERT INTO `movie` (`id`, `name`, `year`) VALUES (1, '星際穿越', '2014'), (2, '大腕', '2001'), (3, '飛馳人生', '2019'), (4, '成為詹姆斯·邦德:丹尼爾·克雷格的故事', '2021'), (5, '空前絕後滿天飛', '1980'), (6, '007:大破天幕殺機', '2012'), (7, '黑客帝國', '1999'), (8, '哈利·波特與魔法石', '2001'), (9, '流浪地球', '2019'), (10, '瘋狂動物城', '2016'), (11, '驚異大奇航', '1987'), (12, '愛樂之城', '2016'), (13, '諜影重重', '2002'), (14, '灰獵犬號', '2020'), (15, '復仇者聯盟4:終局之戰', '2019'), (16, '小森林冬春篇', '2015');
之後,在專案裡新建一個db.js
:
const mysql = require('mysql2/promise')
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'root',
database: 'movie_db'
})
module.exports = connection
然後在app.js
中修改程式碼:
const Koa = require('koa') const Router = require('@koa/router') const router = new Router() const bodyParser = require('koa-bodyparser') const app = new Koa() + const connection = require('./db') router.get('/', ctx => { ctx.body = 'server ok' }) + router.get('/movie', async ctx => { + const res = await connection.then(conn => conn.query('SELECT * FROM movie')) + ctx.body = JSON.stringify(res[0]) + }) app.use(bodyParser()) .use(router.routes()) .listen(3000, () => console.log('server is running at 3000'))
這裡要說明的是,mysql2
中實現了Promise wrapper,在庫層面上支援了Promise的呼叫方式。所以這裡在db.js
裡匯出的只是一個Promise,所以在這裡是不能直接connection.query()
這種同步呼叫方式的,只能用.then(conn => {})
這種形式呼叫。query()
結束後得到的結果裡有兩個物件,第一個是我們要找的資料,而第二個暫時還不知道是什麼,所以這裡直接返回res[0]
以此類推,我們可以寫出其他介面:
router.post('/movie', async ctx => {
const body = ctx.request.body
const res = await connection.then(conn => conn.query('INSERT INTO movie (name, year) VALUES (?, ?)'
, [body.name, body.year]))
.catch(err => console.log(err))
ctx.body = res
})
router.put('/movie/:id', async ctx => {
const id = ctx.params.id
const year = ctx.request.body.year
const res = await connection.then(conn => conn.query('UPDATE movie SET year=? WHERE id=?'
, [year, id]))
.catch(err => console.log(err))
ctx.body = res
})
router.del('/movie/:id', async ctx => {
const id = ctx.params.id
const res = await connection.then(conn => conn.query('DELETE FROM movie WHERE id=?', [id]))
ctx.body = res
})
題外話
為了程式碼格式一致,我在這裡用了一個standard
的工具修復程式碼格式,要啟用這個工具,需要額外加一條:
npm i standard -D
儲存所有檔案,在專案資料夾下執行standard --fix
,即可自動將程式碼格式變成standard強制的樣式