使用json-server模擬REST API

https://segmentfault.com/a/1190000005793257javascript

在開發過程當中,先後端不管是否分離,接口多半是滯後於頁面開發的。因此創建一個REST風格的API接口,給前端頁面提供虛擬的數據,是很是有必要的。php

對比過多種mock工具後,我最終選擇了使用 json server 做爲工具,由於它足夠簡單,寫少許數據,便可使用。
也由於它足夠強大,支持CORS和JSONP跨域請求,支持GET, POST, PUT, PATCH 和 DELETE 方法,更提供了一系列的查詢方法,如limit,order等。下面我將詳細介紹 json server 的使用。css

安裝

首先你的電腦中須要安裝nodejs,建議使用最新版本。而後全局安裝json server.前端

npm install json-server -g

使用linux和macOS的電腦須要加上sudojava

sudo npm install json-server -g

安裝完成後能夠用 json-server -h 命令檢查是否安裝成功,成功後會出現node

json-server [options] <source> 選項: --config, -c Path to config file [默認值: "json-server.json"] --port, -p Set port [默認值: 3000] --host, -H Set host [默認值: "0.0.0.0"] --watch, -w Watch file(s) [布爾] --routes, -r Path to routes file --static, -s Set static files directory --read-only, --ro Allow only GET requests [布爾] --no-cors, --nc Disable Cross-Origin Resource Sharing [布爾] --no-gzip, --ng Disable GZIP Content-Encoding [布爾] --snapshots, -S Set snapshots directory [默認值: "."] --delay, -d Add delay to responses (ms) --id, -i Set database id property (e.g. _id) [默認值: "id"] --quiet, -q Suppress log messages from output [布爾] --help, -h 顯示幫助信息 [布爾] --version, -v 顯示版本號 [布爾] 示例: json-server db.json json-server file.js json-server http://example.com/db.json https://github.com/typicode/json-server

運行

安裝完成後,能夠在任一目錄下創建一個 xxx.json 文件,例如在 mock/ 文件夾下,創建一個 db.json 文件,並寫入如下內容,並在 mock/ 文件夾下執行 json-server db.json -p 3003jquery

{ "news":[ { "id": 1, "title": "曹縣宣佈昨日晚間登日成功", "date": "2016-08-12", "likes": 55, "views": 100086 }, { "id": 2, "title": "長江流域首次發現海豚", "date": "2016-08-12", "likes": 505, "views": 9800 } ], "comments":[ { "id": 1, "news_id": 1, "data": [ { "id": 1, "content": "支持黨中央決定" }, { "id": 2, "content": "抄寫黨章勢在必行!" } ] } ] }

爲了方便,再建立一個 package.json 文件,寫入linux

{ "scripts": { "mock": "json-server db.json --port 3003" } } 

而後使用到 /mock 目錄下執行 npm run mock 命令,若是成功會出現nginx

> @ mock /你的電腦中mock文件夾所在目錄的路徑/mock > json-server db.json -p 3003 \{^_^}/ hi! Loading db.json Done Resources http://localhost:3003/news http://localhost:3003/comments Home http://localhost:3003 

若是不成功請檢查 db.json 文件的格式是否正確。git

操做數據

GET

這個時候訪問 http://localhost:3003/db 能夠查看 db.json 文件中所定義的所有數據。
使用瀏覽器地址欄,jQuery.getfecth({method: "get"}) 訪問 http://localhost:3003/news ,則能夠看到 news 對象下的數據,以Array格式返回:

[ { "id": 1, "title": "曹縣宣佈昨日晚間登日成功", "date": "2016-08-12", "likes": 55, "views": 100086 }, { "id": 2, "title": "長江流域首次發現海豚", "date": "2016-08-12", "likes": 505, "views": 9800 } ]

POST

以jquery的 $.ajax 方法舉例,如下代碼會實時的向 db.json 中的 news 對象push一條新的數據再次用 get 方式訪問 http://localhost:3003/news , 就能夠看到它了

$.ajax({ type: 'post', url: 'http://localhost:3003/news', data: { "id": 3, "title": "我是新加入的新聞", "date": "2016-08-12", "likes": 0, "views": 0 } } )

PUT

一樣以jquery的 $.ajax 方法舉例,如下代碼會實時的對 db.json 中的 news 對象中 id=1 數據進行修改

$.ajax({ type: 'put', url: 'http://localhost:3003/news/1', data: { "title": "曹縣宣佈昨日晚間登日失敗", "date": "2016-08-12", "likes": 55, "views": 100086 } } ) // 結果 [ { "id": 1, "title": "曹縣宣佈昨日晚間登日失敗", "date": "2016-08-12", "likes": 55, "views": 100086 } ]

PATCH 和 DELETE 使用方式同上,就不作演示了。

參考資料

json-server源碼 : json-server
mockjs源碼 : mockjs
demo : 示例代碼

https://segmentfault.com/a/1190000005793320

使用動態數據

上一篇演示時,使用了 db.json 做爲數據載體,雖然方便,可是若是須要大量的數據,則顯得力不從心。
幸虧 json server 能夠經過js動態生成json格式數據,官方例子爲生成1000組user數據:

# /mock/db.js module.exports = function() { var data = { users: [] } // Create 1000 users for (var i = 0; i < 1000; i++) { data.users.push({ id: i, name: 'user' + i }) } return data }

/mock 下運行

json-server db.js -p 3003

咱們訪問 http://localhost:3003/news/ 看到的數據是

[ {"id": 0,"name": "user0"}, {"id": 1,"name": "user1"}, {"id": 2,"name": "user2"}, {"id": 3,"name": "user3"}, ... {"id": 999,"name": "user999"} ] 

可是在開發環境中,name 這個屬性應該是諸如 「李鐵蛋」, 「張豔華」 或者是 「Brenda Thomas」,
「Daniel Wilson」 這樣接地氣的名字,而不是 「user0」, 「user1」 這樣讓人望而生畏的名字,對於用戶的
年齡,性別,籍貫,也應該有比較合理的數據展現。

爲何選擇mockjs

數據生成器有不少,比較出名的有 faker ,chance ,mockjs 等,其中最爲強大的非 faker 莫屬,不但擁有幾乎所有經常使用的數據格式,並且還有中英德法等多種語言的數據。可是在實際測試中發現,faker 對中文數據的支持仍是以西方文字爲基礎,並不能很好的模擬中文,例如:

let faker = require('faker'); faker.locale = "zh_CN"; console.log(faker.address.city()); => 南 羅 console.log(faker.address.streetName()); => 陳 橋 console.log(faker.company.companyName()); => 靜琪 - 越澤 console.log(faker.date.month()); => May console.log(faker.internet.email()); => 87@yahoo.com console.log(faker.phone.phoneNumber()); => 922-61957652

這些看起來有些怪異的中文格式,多半是不能用於國內的數據模擬的,咱們再看看 mockjs 的表現:

let Mock = require('mockjs'); let Random = Mock.Random; console.log(Random.city()); => 珠海市 console.log(Random.cname()); => 韓桂英 console.log(Random.date()); => 2007-08-05 console.log(Mock.mock({ => {stars: '★★★★★'} "stars|1-10": "★" })); Random.image('200x100', '#4A7BF7', 'hello') => 見下圖

雖然 mockj s能夠模擬的數據不如 faker 那麼多,可是因爲其對中文的良好支持,而且使用了位於國內的隨機圖片提供商,顯然是更適合國情的選擇。

mockjs用法示例

請先用15分鐘閱讀 mockjs官方文檔

安裝mockjs

/mock 目錄下安裝

npm install mockjs --save

Mock.mock

我知道有些人不會去認真的閱讀官方文檔,因此在此摘抄一些官方文檔中的例子做爲示範:

// repeat 方法(部分) Mock.mock({ "string|5": "★" => "string": "★★★★★" "string|1-10": "★" => "string": "★★" "number|1-100": 100 => "number": 85 "number|1-100.2": 100 => "number": 25.69 })

 

Mock.Random

我知道有些人不會去認真的閱讀官方文檔,因此在此摘抄一些官方文檔中的例子做爲示範:

// random 方法(部分) Random.integer(60, 100) => 78 Random.float(60, 100) => 89.565475 Random.range(60, 100) => [60,61,62,...,99] Random.date() => "2018-12-28" Random.image('200x100','#396') => "http://dummyimage.com/200x100/396" Random.color() => "#79d8f2" (默認使用hex顏色) Random.county(true) => "浙江省 舟山市 岱山縣"

爲何不在瀏覽器中使用mockjs

經過閱讀 mockjs 的官方文檔能夠發現,它實際上是做爲一個獨立的 mock server 存在的,就算沒有json server,同樣能夠反饋數據,可是因爲如下一些缺點,讓我只能把它做爲一個數據構造器來使用:

  • 不能跨域使用

  • 與某些框架中的路由處理邏輯衝突

  • 沒法定義複雜的數據結構,好比下面的數據結構,images 將會是字符串 [object object], 而非預想中的數組:

Mock.mock({ "list|1-10": [ "id|+1": 1, "images": [1,2,3] ] })
  • 沒法自定義較爲複雜的路由

示例

下面是一個使用 mockjs 構造的比較複雜的數據格式,對象是一個新聞列表,其中有100條新聞,每條新聞有對應的id,標題,內容,簡介,標籤,瀏覽量,和一個圖片數組:

# /mock/db.js let Mock = require('mockjs'); let Random = Mock.Random; module.exports = function() { var data = { news: [] }; var images = [1,2,3].map(x=>Random.image('200x100', Random.color(), Random.word(2,6))); for (var i = 0; i < 100; i++) { var content = Random.cparagraph(0,10); data.news.push({ id: i, title: Random.cword(8,20), desc: content.substr(0,40), tag: Random.cword(2,6), views: Random.integer(100,5000), images: images.slice(0,Random.integer(1,3)) }) } return data } 

/mock 下運行

json-server db.js -p 3003

訪問 http://localhost:3003/news 看到的數據是:

[ { "id": 0, "title": "元小總小把清保住影辦歷戰資和總由", "desc": "共先定製向向圓適者定書她規置鬥平相。要廣確但教金更前三響角面等以白。眼查何參提適", "tag": "值集空", "views": 3810, "images": [ "http://dummyimage.com/200x100/79f2a5&text=別角置", "http://dummyimage.com/200x100/f28279&text=收面幾容受取", "http://dummyimage.com/200x100/7993f2&text=作件" ] }, { "id": 1, "title": "物器許條對越復術", "desc": "方江周是府整頭書生權部部條。始克識史但給又約同段十子按者感律備。關長廠平難山從合", "tag": "分七眼術保", "views": 4673, "images": [ "http://dummyimage.com/200x100/79f2a5&text=別角置" ] }, { "id": 2, "title": "但學卻連質法計性想般最", "desc": "以羣親它天即資幾行位具回同務度。場養驗快但部光天火金時內我。任提教毛辦結論感看還", "tag": "響六", "views": 4131, "images": [ "http://dummyimage.com/200x100/79f2a5&text=別角置", "http://dummyimage.com/200x100/f28279&text=收面幾容受取", "http://dummyimage.com/200x100/7993f2&text=作件" ] }, ... { "id": 99, "title": "則羣起然線部其深我位價業紅候院", "desc": "爲高值務須西生型住斷況裏聽。志置開用她你然始查她響元還。照員給門次府此據它後支越", "tag": "何你", "views": 2952, "images": [ "http://dummyimage.com/200x100/79f2a5&text=別角置" ] } ]

參考資料

json-server源碼 : json-server
mockjs源碼 : mockjs
demo : 示例代碼

https://segmentfault.com/a/1190000005793520

配置項

在安裝好json server以後,經過 json-server -h 能夠看到以下配置項:

json-server [options] <source> Options: --config, -c 指定 config 文件 [默認: "json-server.json"] --port, -p 設置端口號 [default: 3000] --host, -H 設置主機 [默認: "0.0.0.0"] --watch, -w 監控文件 [boolean] --routes, -r 指定路由文件 --static, -s 設置靜態文件 --read-only, --ro 只容許 GET 請求 [boolean] --no-cors, --nc 禁止跨域資源共享 [boolean] --no-gzip, --ng 禁止GZIP [boolean] --snapshots, -S 設置快照目錄 [默認: "."] --delay, -d 設置反饋延時 (ms) --id, -i 設置數據的id屬性 (e.g. _id) [默認: "id"] --quiet, -q 不輸出日誌信息 [boolean] --help, -h 顯示幫助信息 [boolean] --version, -v 顯示版本號 [boolean] Examples: bin db.json bin file.js bin http://example.com/db.json

既能夠經過命令行方式單行配置,如

json-server db.js -p 3003 -d 500 -q -r ./routes.json

,也能夠經過 json-server.json 文件進行配置後:

# /mock/json-server.json { "host": "0.0.0.0", "port": "3003", "watch": false, "delay": 500, "quiet": true, "routes": "./routes.json" }

運行

json-server db.js

返回靜態文件

/mock 下創建 public 目錄,便可直接訪問其下的全部靜態文件,包括但不限於
js, css ,markdown 文件等。

地址欄輸入 http://localhist:3003/readme.md 便可訪問如下文件

# /mock/public/readme.md # hello Mr DJ,這節奏不要停

移動設備訪問

經過 json server 創建的rest api服務默承認以在局域網中經過WIFI訪問接口。
windows下面經過 ipconfig 查找到電腦的局域網地址.mac設備是經過 ifconfig | grep "inet " | grep -v 127.0.0.1 查看。
好比個人電腦局域網ip是 192.168.0.6,在手機上訪問 http://192.168.0.6:3003 便可。

自定義路由

能夠經過自定義路由的形式,簡化數據結構,或是創建高彈性的web api,例如

# /mock/routes.json { "/news/:id/show": "/news/:id", "/topics/:id/show": "/news/:id", }

訪問 /news/1/showtopics/1/show 均返回指定的 /news/1 內容。

* 須要注意的是,路由必須以 / 開頭

npm啓動

相比在終端中直接輸入各類命令,我更喜歡利用 node scripts 來處理任務,在 /mock 下創建文件 package.json,而後運行 npm run mock

# /mock/package.json { "scripts": { "mock": "json-server db.js" } } 

 

數據過濾

數據過濾是 json server 中很是強力的功能。經過url上簡單的query字段,便可過濾出各類各樣的數據。
示例數據源:

[ { "id": 0, "title": "元小總小把清保住影辦歷戰資和總由", "desc": "共先定製向向圓適者定書她規置鬥平相。要廣確但教金更前三響角面等以白。眼查何參提適", "tag": "值集空", "views": 3810, "images": [ "http://dummyimage.com/200x100/79f2a5&text=別角置", "http://dummyimage.com/200x100/f28279&text=收面幾容受取", "http://dummyimage.com/200x100/7993f2&text=作件" ] }, { "id": 1, "title": "物器許條對越復術", "desc": "方江周是府整頭書生權部部條。始克識史但給又約同段十子按者感律備。關長廠平難山從合", "tag": "分七眼術保", "views": 4673, "images": [ "http://dummyimage.com/200x100/79f2a5&text=別角置" ] }, { "id": 2, "title": "但學卻連質法計性想般最", "desc": "以羣親它天即資幾行位具回同務度。場養驗快但部光天火金時內我。任提教毛辦結論感看還", "tag": "響六", "views": 4131, "images": [ "http://dummyimage.com/200x100/79f2a5&text=別角置", "http://dummyimage.com/200x100/f28279&text=收面幾容受取", "http://dummyimage.com/200x100/7993f2&text=作件" ] }, ... { "id": 99, "title": "則羣起然線部其深我位價業紅候院", "desc": "爲高值務須西生型住斷況裏聽。志置開用她你然始查她響元還。照員給門次府此據它後支越", "tag": "何你", "views": 2952, "images": [ "http://dummyimage.com/200x100/79f2a5&text=別角置" ] } ]

屬性值(Filter)

使用 . 操做對象屬性值

// 獲取圖片數量爲3,且標籤字數爲2的新聞 GET /news?images.length=3&tag.length=2 

分割(Slice)

使用 _start_end 或者 _limit (response中會包含 X-Total-Count)

// 獲取id=10開始的5篇新聞 GET /news?_start=10&_limit=5 // 獲取id=20開始,id=35結束的新聞 GET /news?_start=20&_end=35

排序(Sort)

使用 _sort_order (默認使用升序(ASC))

// 按照瀏覽數量降序排列 GET /news?_sort=views&_order=DESC 

運算符(Operators)

使用 _gte_lte 選取一個範圍

// 選取瀏覽量在2000-2500之間的新聞 GET /news?views_gte=2000&views_lte=2500

使用 _ne 排除一個值

// 選擇tag屬性不是 "國際新聞" 的分類 GET /news?tag_ne=國際新聞

使用 _like 進行模糊查找 (支持正則表達式)

// 查找title中含有 "前端" 字樣的新聞 GET /news?title_like=前端

全文檢索(Full-text search)

使用 q,在對象所有value中遍歷查找包含指定值的數據

// 查找新聞所有字段包含 "強拆" 字樣的數據 GET /news?q=強拆

關係圖譜(Relationships)

獲取包含下級資源的數據, 使用 _embed

GET /news?_embed=comments GET /news/1?_embed=comments

獲取包含上級資源的數據, 使用 _expand

GET /news?_expand=post GET /news/1?_expand=post

 

做爲中間件

除了獨立做爲rest api 服務器以外, json server 一樣能夠做爲諸如 Express 之類框架的中間件使用,具體API詳見 json server模塊

參考資料

json-server源碼 : json-server
mockjs源碼 : mockjs
demo : 示例代碼

相關文章
相關標籤/搜索