### GDSC NYUST x 資訊創客社
<br>
### JS後端與資料庫讀書會
#### Express 課程
<br>
#### 2023/11/15 ( Wed ) 19:00 - 21:00
#### 講師:蘇祐民 *YoMin Su*
#### 本次課程影片:(⚒️製作中)
<img src="" height="200px">
---
## 課程簡介
----
### 簡單的說
- 認識Express
- 建立自己的Express應用程式
- 部屬Express應用程式
----
### 複雜點講
- 認識Express
- 建立Node專案並安裝Express
- 建立基本Express應用
- 如何定義Express路由
- 設計Express Middleware
- 透過Express實作RESTful API
- 整合資料庫(SQLite)
- 部署Express與設定網頁伺服器
---
## 初見 Express.js
----
### Express 是誰設計的?
原作者是<span class="orange">TJ Holowaychuk</span>,他同時也是另一個有名的框架,<span class="bluegreen">Koa</span>的作者,所以這兩者可謂系出同源!
在經過幾次的管理轉移後,目前Express是由Node.js基金會負責管理~
> Express也被稱為是Node.js的伺服器框架的『事實標準』
----
### Express 可以做什麼?
- 後端邏輯處理
- 網頁伺服器
- 檔案下載網站
- etc...
> 基本上透過HTTP請求的方式,都是可以的
----
### 今日目標
- 寫個簡單的Express範例
- 嘗試串接SQLite資料庫
- 將Express與網頁伺服器整合
---
## 建立Node.js專案
----
### 找個喜歡的資料夾

----
### 初始化專案

----
### 將Express加入到專案中

---
## 來寫應用吧
----
### 先新增個檔案

----
### 基本程式碼
```javascript=
const express = require('express');
let app = express();
app.get('/', (req, res, next) => {
res.status(200).send('Hello!');
});
app.listen(3000, () => {
console.log("Express is running!");
});
```
----
### 剛剛那個在幹嘛?
- app: 建立Express的實例
- app.get(): 讓Express透過GET方法進行監聽
- app.listen(): 在系統上哪個位置工作
----
### 如何處理路由?
路由也可以被稱為資源路徑,是用於區分不同內容的功能!
在Express中,有兩種方式可以使用,分別來說明~
----
### 標準用法
```javascript=
app.get('url');
app.post('url');
app.put('url'); /*或是*/ app.patch('url');
app.delete('url')
```
以上四種都是基本可以使用的方式,在url的字串欄位填入你希望的路徑就可以了!
Example:
```javascript=
app.get('/');
app.post('/user');
app.delete('/user/topic');
```
----
### 標準的延伸
```javascript=
app.route('/url')
.get((req, res) => {})
.post((req, res) => {})
.delete((req, res) => {});
```
透過.route方法,可以直接幫指定的路徑加上對應的HTTP Method
----
### 第二種方式
透過express.Router是另一種可以達到相同效果的作法,若需要比較容易維護的架構,可以考慮這種方式:
```javascript=
const express = require('express');
var router = express.Router();
router.use(/*Code here*/);
router.get(/*Code here*/);
router.post(/*Code here*/);
module.exports = router;
```
----
### 第二種方式(2)
上面為router本身,接著要在主要檔案中引入
```javascript=
const express = require('express');
let app = express();
const paths = require('./filename.js');
app.use('/path', paths);
```
----
### 中介層
當你希望在路由進入前做點什麼,或是在離開後做點什麼,就會用到它
Example:
```javascript=
const express = require('express');
let app = express();
app.use((req, res, next) => {
console.log("Something happened: ", Date.now());
next();
});
app.get(/*Code here*/);
app.use((error, req, res, next) => {
console.log("Error out: ", error);
});
```
----
### 若希望幫中介層加入參數
可以透過return function的方式使用,範例如下
```javascript=
function middle(aaa, bbb) {
return (req, res, next) => {
console.log(aaa, bbb);
}
}
app.use(middle('123', 'abc'));
```
---
## RESTful API
----
### 簡介
就像我們在期中考前所提到的:
- Uniform Interface:統一介面。
- Stateless:無狀態。
- Cacheable:可快取。
- Client-Server:客戶伺服器分離模式,任何一個客戶端與伺服器都是可替換的。
- Layered System:分層的系統,客戶端不知道他聯絡的是不是最終伺服器。
----
### 在Express中實作
我們可以透過標準的幾個HTTP方法達到RESTful的格式,範例如下:
```javascript=
const express = require('express');
let app = express();
let person = [];
app.use(express.urlencoded());
app.use(express.json());
app.route('/user')
.get((req, res) => {
res.status(200).send(person.toString())
})
.post((req, res) => {
console.log(req.body);
person.push(req.body.person);
res.status(200).send('Add Success');
})
.patch((req, res) => {
res.status(200).send('Method not work');
})
.delete((req, res) => {
person = person.filter(p => p != req.body.person);
res.status(200).send("Delete Success")
});
app.listen(3000, () => {
console.log("Express is running!");
});
```
----
### 測試時間
取得資料內容:
```bash=
curl localhost:3000/user
```
加入一筆紀錄:
```bash=
curl -X POST -H "Content-Type: application/json" --data '{"person":"YoMin"}' localhost:3000/user
```
修改紀錄:
```bash=
curl -X PATCH localhost:3000/user
```
刪除一筆紀錄:
```bash=
curl -X DELETE -H "Content-Type: application/json" --data '{"person":"YoMin"}' localhost:3000/user
```
---
## 來個資料庫吧
----
### 安裝SQLite

----
### 來改寫剛剛的範例
```javascript=
const express = require('express');
let app = express();
const dbFile = './person.db';
const sqlite = require('sqlite3').verbose();
let db = new sqlite.Database(dbFile);
db.serialize(() => {
db.run("CREATE TABLE person (name TEXT)");
});
app.use(express.urlencoded());
app.use(express.json());
app.route('/user')
.get((req, res) => {
let person = '';
db.serialize(() => {
db.each("SELECT name FROM person", (err, row) => {
res.status(200).send(row.name);
});
});
})
.post((req, res) => {
db.serialize(() => {
db.run("INSERT INTO person VALUES (?)", [req.body.person]);
});
res.status(200).send('Add Success\n');
})
app.listen(3000, () => {
console.log("Express is running!");
});
```
----
### 測試時間
取得資料內容:
```bash=
curl localhost:3000/user
```
加入一筆紀錄:
```bash=
curl -X POST -H "Content-Type: application/json" --data '{"person":"YoMin"}' localhost:3000/user
```
---
## 串接網頁伺服器
----
### 拿nginx作為範例
```nginx=
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
location / {
proxy_pass http://127.0.0.1:3000;
}
}
```
----
### 重新啟動網頁伺服器
```bash=
sudo service nginx restart
```
----
### 改透過網頁伺服器確認是否可以連線
```bash=
curl localhost/user
```
---
## 課程回顧 | Q&A
----
### 今天了解到
- Express基礎
- Express路由
- Express中介層
- CRUD操作
- 串接SQLite
- 透過網頁伺服器反向代理
----
### Q & A
有任何問題嗎?
----
### 學習資源
- [MDN](https://developer.mozilla.org/zh-TW/docs/Learn/Server-side/Express_Nodejs)
- [Express.js](https://expressjs.com/zh-tw/)
---
## Bye Bye

<style>
.orange {
color: #FF8800;
}
.red {
color: #FF0000;
}
.bluegreen {
color: #00FFCC;
}
.gray {
color: #272727;
}
.blue {
color: #00E3E3
}
</style>
{"title":"建立現代後端應用程式入門","slideOptions":"{\"transition\":\"concave\",\"allottedMinutes\":100}","description":"YoMin Su","contributors":"[{\"id\":\"f8142aa2-66aa-4867-821d-2f1ffff7a7ba\",\"add\":6388,\"del\":27}]"}