# json-server 環境教學 - 打造自己的作品
## 為什麼要安裝 postman?
[POSTMAN 官網](https://www.postman.com/) 至官網直接安裝

### 優勢
1. 各種類型的網路請求,例如 get post put patch del
2. API網址
3. 回傳的內容,例如 GET 可以取得JSON 資料
4. 方便快速測試,不用在撰寫JS,即可測試API
5. 側邊欄可以整理整合
---
## json-server
### 安裝
[json-server GitHub](https://github.com/typicode/json-server)
Install JSON Server :
需要進入終端機後(win 可用 crtl + R 輸入 cmd d)
```
npm install -g json-server
```
Create a db.json file with some data :
創建一個 db.json 的檔案 ,需要在C槽底下,範例格式如下
```
{
"posts": [
{ "id": 1, "title": "json-server", "author": "typicode" }
],
"comments": [
{ "id": 1, "body": "some comment", "postId": 1 }
],
"profile": { "name": "typicode" }
}
```
Start JSON Server :
於終端機,首先需要cd使終端機進入到資料夾(圖1),輸入以下指令 (圖2),即可開啟JSON 伺服器(圖3),恭喜可以開始你的API操作了~
```
json-server --watch db.json
```
圖1

圖2

圖3

---
## json-server 與一般常見伺服器架構差異介紹

一般的前端後端的做法如上圖
```
1. 前端瀏覽器使用API向伺服器請求
2. 伺服器再從資料庫取得資料
3. 資料庫回傳給伺服器
4. 伺服器再傳給前端瀏覽器資料
```

json-server步驟如上圖
```
1. 前端瀏覽器使用API發出請求
2. json-server 使用node.js + express 架成模擬用伺服器
3. 伺服器直接從本地端只取得"一次"的 db.json,記錄在本身的記憶體中
4. 伺服器再傳給前端瀏覽器資料
```

```
將 API伺服器 與 網頁分開,類似於前後端分離
```
---
## 新增網頁,來讀取自己打造的 json-server API

json-server需要是開啟的狀態下,如果是關閉則會出現錯誤
此處範例有三個API,下圖為posts的json資料

使用這三個API,透過AJAX向伺服器取得新增.....等等操作資料
範例程式碼如下:
html
```
<h1>JSON-server 測試</h1>
<button id="postApi" type="button" click="postApi()">新增</button>
<button id="getApi" type="button" click="getApi()">取得</button>
<script src="https://unpkg.com/axios@1.1.2/dist/axios.min.js"></script>
<script src="./all.js"></script>
```
js
```
// 新增API
const post = document.querySelector('#postApi')
post.addEventListener('click',(e)=> {
postApi()
})
function postApi() {
axios.post('http://localhost:3000/posts',
{
"title": "json-server2",
"author": "typicode2"
})
.then((res)=> {
console.log(res);
})
}
//取得API
const get = document.querySelector('#getApi')
get.addEventListener('click',(e)=> {
getApi()
})
function getApi() {
axios.get('http://localhost:3000/posts')
.then((res)=> {
console.log(res);
})
}
```
---
## db.json 架構設計

1. 開頭須為物件
2. 第一個物件的key值,會被視為API網址
3. 建議為陣列存放資料
(因如果替換修改資料,物件需要整筆覆蓋才可修改資料,例如profile)
4. 以物件新增存放各筆資料
如下為自己新增的API,空陣列,新增資料會為物件格式。
```
{
"apiName": []
}
```
---
## json-server API 各種使用功能
### Filter 篩選
以?串接
* 物件名 = 值
例如: ?title=json-server
則會篩選資料中title 是 json-server 的資料
同時搜尋各種條件,以&串接
例如: ?id=1&id=2
亦可以針對內部屬性搜尋
例如: ?author.name=typicode
```
GET /posts?title=json-server&author=typicode
GET /posts?id=1&id=2
GET /comments?author.name=typicode
```
### Full-text search 關鍵字搜尋
以?串接,
* q=關鍵字內容
`GET /posts?q=internet`
### Paginate 分頁
以?串接,
* _page 第幾頁
* _limit 限制一頁有幾筆資料(自動將資料做分頁)
預設是返回10筆資料
```
GET /posts?_page=7
GET /posts?_page=7&_limit=20
```
### sort 排序
* _sort 依所填值為條件排序
* _order 排序方式
asc 為 低到高 (小到大) // desc為 高到低 (大到小)
```
GET /posts?_sort=views&_order=asc
GET /posts/1/comments?_sort=votes&_order=asc
```
亦可複數條件做篩選
```
GET /posts?_sort=user,views&_order=desc,asc
```
### Operators 區間篩選
* _gte 起始值
* _lte 終點值
`GET /posts?views_gte=10&views_lte=20`
* _ne 包含值
`GET /posts?id_ne=1`
* _like 過濾器 (支持正則表達式)
`GET /posts?title_like=server`
---
## todolist restful API練習

* 檔案下載
[ APIcode.zip](https://cdn.fs.teachablecdn.com/E69DnOCwQtOzndkAhrFR)
* CodePen
[本地端 Codepen 代辦事項練習
](https://codepen.io/hexschool/pen/OJWRqrN?editors=1010)
html
```
<input type="text" class="txt" placeholder="請輸入待辦事項">
<input type="button" class="save" value="儲存待辦">
<ul class="list"></ul>
```
js
```
const txt = document.querySelector('.txt');
const save = document.querySelector('.save');
const list = document.querySelector('.list');
let data = [];
function renderData(){
let str = '';
data.forEach(function (item,index) {
str+=`<li>${item.content} <input class="delete" type="button" data-num="${index}" value="刪除待辦"></li>`
})
list.innerHTML = str;
}
// 新增待辦功能
save.addEventListener('click',function(e){
if (txt.value=="") {
alert("請輸入內容");
return;
}
let obj = {};
obj.content = txt.value
data.push(obj);
renderData();
})
// 刪除待辦功能
list.addEventListener("click",function(e){
if(e.target.getAttribute("class")!=="delete"){
return;
}
let num = e.target.getAttribute("data-num");
console.log(num);
data.splice(num,1);
alert("刪除成功!");
renderData();
})
```