# REST與RESTful API
## REST
### 概述
* REST全名為**Representational State Transfer**(表現層狀態轉換),為奠基於HTTP協議的World Wide Web(WWW)架構設計風格,目的是讓不同的程式在網際網路中相互傳遞資訊
### 原則
1. 用戶端-伺服器Client-Server
* 使用者介面與伺服器資料儲存的關注點分離
2. 無狀態Stateless
* 每一個用戶端的請求必須包含所有必要資訊,伺服器不會保留前一個請求的任何狀態,即每一個請求皆完全獨立
* 無狀態意旨伺服器獨立於所有之前的請求,所以用戶端可以按任何順序去請求資源
3. 可快取性Cacheability
* 用戶端從伺服器獲得資源後,若此資源未再被變更,則後續直接由cache取用本地資源,不需再向伺服器發出請求
* 良好的快取機制可減少用戶端及伺服器間的請求及回應,提高互動效率
4. 統一介面Uniform Interface
* 簡化系統架構,以減少[耦合性](https://ithelp.ithome.com.tw/articles/10191761),使所有模組各自獨立
* 提供統一的操作方式與規格
5. 分層系統Layered System
* 各伺服器藉由系統劃分為不同層次,每層各自獨立,可專責特定功能、個別實施不同的安全策略,便於管理及維護,也提高系統整體安全性
* 藉由負載均衡、共享快取來提升性能
6. 按需代碼Code-On-Demand (optional)
* 伺服器可隨時傳送程式碼擴充新功能,以因應用戶端的需求
## RESTful API
### 概述
* 依循REST架構風格的API稱為RESTful API
### 組成元件
1. 資源位址`URI`
* `URI`(Uniform Resource Identifier):區分不同資源的獨一無二識別碼,屬於通用概念,具體方法包含`URL`及`URN`
* `URN`(Uniform Resource Name):利用名稱識別資源
* `URL`(Uniform Resource Locator):利用位址識別資源
2. 傳輸資源的類型,如`JSON`、`XML`、`YAML`
3. 對傳輸資源的操作,如`HTTP`請求方法:`GET`、`POST`、`DELETE`等
### 總結
* RESTful API提供簡單、高效率且靈活的方式進行設計及開發,讓不同的系統更容易整合
### 參考文章
* [API 是什麼? RESTful API 又是什麼?](https://medium.com/itsems-frontend/api-是什麼-restful-api-又是什麼-a001a85ab638)
* [什麼是 RESTful API?](https://www.explainthis.io/zh-hant/swe/restful-api)
* [REST - Wikipedia](https://en.wikipedia.org/wiki/REST)
* [HTTP - Wikipedia](https://en.wikipedia.org/wiki/HTTP)
# 同步與非同步
### 概述
* JavaScript屬於**單執行緒**(Single-Thread)語言,一次只處理一件事
* 在同步的情況下,程式碼會逐行執行,而在非同步的情況下,則無需等待前一個指令完成,就執行後續的程式碼
* 非同步對於網頁瀏覽很重要,可避免阻塞(Blocking)
### 關於`Callback Function`與非同步
* 可用於控制特定函式的執行時機
* 可作為引數(argument)被傳入另一個函式參數中並執行的函式
```javascript
function printFirst (callbackFn) {
console.log ('First!');
callbackFn();
};
function printLater () {
console.log ('Later!');
};
printFirst(printLater);
// output
// First!
// Later!
```
### 常見的`callback function`
如Web API中的`addEventListener()`、`setTimeout()`等
* 由於`setTimeout()`屬於非同步事件,即便`printFirst`函式中定義的時間為0,`printLater`函式仍然會先執行
```javascript
function printFirst () {
setTimeout (function () {
console.log ('First')
}, 0) // 間隔時間0秒
};
function printLater () {
console.log ('Later!');
};
printFirst();
printLater();
// output
// Later!
// First!
```
* 利用`callback function`搭配`setTimeout()`控制函式的執行時機
```javascript
function printFirst (callbackFn) {
setTimeout (function () {
console.log ('First!');
callbackFn();
}, 3000)
};
function printLater () {
console.log ('Later!');
}
printFirst(printLater);
// output
// (間隔時間3秒)
// First!
// Later!
```
### `Callback function`的缺點:Callback Hell
* 堆疊的巢狀結構難以閱讀及維護
```javascript
a (function (rtnA) {
b (rtnA, function (rtnB) {
c (rtnB, function (rtnC) {
d (rtnC, function (rtnD) {
e (rtnD, function (rtnE) {
f (rtnE, function (rtnF) {
console.log (rtnF);
// CALLBACK HELL!!
})
})
})
})
})
})
```
* 可利用`Promise`解決
### 利用`Promise`處理非同步
#### 概述
* `Promise`屬於物件,其建構函式接收`executor function`執行函式的兩個參數:`resolve`、`reject`,分別表示非同步操作成功或失敗,回傳結果後表示`promise`事件結束
```javascript
new Promise ( /* executor */ function (resolve, reject) {
...
resolve();
reject();
})
```
#### 狀態
* 共有三種狀態:等待中`pending`、已完成`fulfilled`、已拒絕`rejected`
* `Promise`初始狀態為`pending`,`resolve`用於將`promise`的狀態由`pending`轉變為`fulfilled`,表示非同步操作成功
* 反之,`reject`用於將`promise`的狀態由`pending`轉變為`rejected`,表示非同步操作失敗
#### `Promise`原型方法
* 利用`.then()`搭配`.catch()`分別取得操作成功及失敗的結果
```javascript
let testPromise = new Promise ((resolve, reject) => {
let condition = true;
if (condition) {
setTimeout (() => {
resolve('succeeded'); // 成功時回傳值
}, 3000);
} else {
reject('failed'); // 失敗時回傳值
};
});
testPromise
.then ((msg) => {
console.log (msg);
})
.catch ((errMsg) => {
console.log (errMsg);
})
```
* 補充:`.then()`方法可帶入兩個callback function : `onFulfilled`, `onRejected`做為參數,同樣可分別取得操作成功及失敗的成果,以上面的範例進行改寫:
```javascript
let testPromise = new Promise ((resolve, reject) => {
let condition = false;
if (condition) {
setTimeout (() => {
resolve('succeeded');
}, 30);
} else {
reject('failed');
};
});
testPromise
.then ((msg) => {
console.log (msg);
}, (errMsg) => {
console.log(errMsg)
})
```
#### Promise Chaining
* `.then()`及`.catch()`皆可進行串聯傳遞結果,故可利用此特性來避免製造callback hell
* `return`回傳的`promise`物件可再進一步被取用
```javascript
function testPromise (condition) {
return new Promise ((resolve, reject) => {
condition ? resolve (``) : reject (`failed`);
});
}
testPromise (true)
.then (resolve => {
console.log (`succeeded(1)`)
return testPromise (true)
})
.then (resolve => {
console.log (`succeeded(2)`)
return testPromise (false) // 於此行進入catch
})
.then (resolve => {
console.log (`succeeded(3)`) // 故第三次成功的結果不會印出
return testPromise (true)
})
.catch (reject => {
console.log (`failed(1)`)
return testPromise (false)
})
.catch (reject => {
console.log (`failed(2)`)
})
// output
// succeeded(1)
// succeeded(2)
// failed(1)
// failed(2)
```
### 參考文章
* [JavaScript 什麼是Callback函式 (Callback Function)?](https://matthung0807.blogspot.com/2019/05/javascript-callback-callback-function.html)
* [Promise - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
* [[教學] JavaScript Promise 的用法](https://www.shubo.io/javascript-promise/)
# AJAX技術
### Fetch
* JavaScript用於完成HTTP請求的原生方法,在ES6前只有`XMLHttpRequest`,ES6新增`Fetch`
* 基於`Promise`所開發:回傳物件使用`.then()`、`.catch()`...等方法
#### 基本用法
* 回傳的`ReadableStream`物件需針對不同資料類型使用不同的解析方法,才能取得需要的資料
* `.blob()` ([binary large object](https://hackmd.io/@l-zHCaalQSq59NxFixnqyg/rkvXJlCG5))、`.json()`、`.text()`...
* `GET`請求
```javascript
fetch ('https://...')
.then((response) => {
return response.json(); // 解析為JSON物件
})
.then((data) => {
console.log (data); // 進一步取得資料
})
```
### Axios
* 環境安裝:利用[CDN](https://github.com/axios/axios)
* 和`Fetch`一樣基於`Promise`所開發
#### 基本用法
* `GET`請求
```javascript
axios.get ('https://...')
.then((response) => {
console.log (response.data);
})
.catch((error) => {
console.log (error)
})
```
* `POST`請求
```javascript
axios.post('url', {
email: 'example@gmail.com',
password: '0000'
})
.then((response) => {
console.log (response)
})
.catch((error) => {
console.log (error)
})
```
### 參考文章
* [Fetch - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/API/fetch)
* [Web APIs - 使用原生 Fetch API 獲取遠端資料](https://awdr74100.github.io/2020-08-08-webapis-fetch/)
* [axios | GitHub](https://github.com/axios/axios)