在開發(fā)過程中,接口多半是滯后于頁面開發(fā)的。利用JSON Server快速搭建模擬返回REST風格的后臺數(shù)據(jù),保證前后端開發(fā)的分離。前后端開發(fā)只要設定好接口以及數(shù)據(jù)的定義,剩下的就可以各自開發(fā),最后集成測試。
JSON Server 作為工具,基于Express開發(fā),而且它足夠簡單,寫少量數(shù)據(jù),即可使用,支持CORS和JSONP跨域請求,支持GET, POST, PUT, PATCH 和 DELETE 方法,更提供了一系列的查詢方法,如limit,order等
安裝
npm install json-server -g
全局安裝,可以在命令行下獨立執(zhí)行。安裝完成后可以用 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 監(jiān)控文件 [boolean]
--routes, -r 指定路由文件
--static, -s 設置靜態(tài)文件
--read-only, --ro 只允許 GET 請求 [boolean]
--no-cors, --nc 禁止跨域資源共享 [boolean]
--no-gzip, --ng 禁止GZIP [boolean]
--snapshots, -S 設置快照目錄 [默認: "."]
--delay, -d 設置反饋延時 (ms)
--id, -i 設置數(shù)據(jù)的id屬性 (e.g. _id) [默認: "id"]
--quiet, -q 不輸出日志信息 [boolean]
--help, -h 顯示幫助信息 [boolean]
--version, -v 顯示版本號 [boolean]
啟動
創(chuàng)建一個目錄server,在該目錄下創(chuàng)建一個json文件,db.json.
{
"list": [
{
"id": 1,
"name": "張三",
"tel": "15223810923"
},
{
"id": 2,
"name": "李四",
"tel": "15223810923"
},
{
"id": 3,
"name": "王二",
"tel": "15223810923"
},
{
"id": 4,
"name": "陳五",
"tel": "15223810923"
},
{
"name": "趙六",
"tel": "123454323",
"id": 5
},
{
"name": "趙六",
"tel": "123454323",
"id": 6
},
{
"name": "趙六",
"tel": "123454323",
"id": 7
}
],
"users": [
{
"id": 1,
"name": "陳五",
"sex":"male",
"tel": "12345678",
"auther":{
"name":"陳五",
"age":"25"
}
},
{
"id": 2,
"name": "王二",
"sex":"male",
"tel": "15223810923",
"auther":{
"name":"王二",
"age":"22"
}
}
],
"user": {
"id": 1,
"name": "陳五",
"tel": "15223810923"
}
,
"posts": [
{ "id": 1, "title": "json-server", "author": "typicode" }
],
"comments": [
{ "id": 1, "body": "some comment", "postId": 1 }
],
"profile": { "name": "typicode" }
}
在server目錄下執(zhí)行
json-server db.json -p 3003
打開瀏覽器,http://localhost:3003,查看頁面。如果要監(jiān)控json文件的變化,啟動的時候加上參數(shù)--watch。
支持的方法
以APIhttp://localhost:3003/list 為例
- GET /list 獲取列表
- GET /list/1 獲取id=1的數(shù)據(jù)
- POST /list 創(chuàng)建一個項目
- PUT /list/1 更新一個id為1的數(shù)據(jù)
- PATCH /list/1 部分更新id為1的數(shù)據(jù)
- DELETE /list/1 刪除id為1的數(shù)據(jù)
對于對象,例如http://localhost:3003/user,地址是相同的。
- GET /user
- POST /user
- PUT /user
- PATCH /user
- 當你發(fā)送POST,PUT,PATCH 或者 DELETE請求時,變化會自動安全的保存到你的db.json文件中。
- 你的請求體body應該是封閉對象。比如
{"name": "Foobar"} - id不是必須的,在PUT或者PATCH方法中,任何的id值將會被忽略。
- 在POST請求中,id是可以被添加的,如果該值沒有沒占用,會使用該值,否則自動生成。
- POST,PUT或者PATCH請求應該包含一個
Content-Type:application/json的header,來確保在請求body中使用json。
高級查找
Filter
用.來訪問深層屬性,比如
GET /users?set=male&tel=12345678
GET /list?id=1&id=2
GET /users?author.age=25
Paginate
使用 _page 和可選的 _limit來對返回數(shù)據(jù)定制(不設置默認返回10條)。
在返回的header中,有一個屬性Link,里面會有first, prev, next and last links。
header中還有一個屬性X-Total-Count,用來存儲滿足條件的數(shù)據(jù)的條數(shù)。
GET /list?_page=1
GET /list?_page=2&_limit=2
Sort
使用 _sort 和 _order (默認是ascending)
GET /list?_sort=id&_order=asc
對于多字段的排序,可以參考下面的格式:
GET /list?_sort=id,name&_order=desc,asc
Slice
使用_start和_end或_limit(一個 X-Total-Count 自定義Header在Response里面),就像數(shù)據(jù)的slice的方法一樣。
GET /list?_start=2&_end=5
GET /list?_start=2&_limit=5
Operators
用 _gte或_lte來得到一個范圍。
GET /list?id_gte=2&id_lte=5
用_ne來不包含(exclude)一個值
GET /posts?id_ne=1
GET /list?id_gte=2&id_lte=5&id_ne=4
用 _like 來 filter (RegExp 支持)
GET /list?name_like=王
search
使用q
GET /list?q=1
Relationships
關聯(lián)子資源, 添加_embed
GET /posts?_embed=comments
GET /posts/1?_embed=comments
包含父資源, 添加_expand
GET /comments?_expand=post
GET /comments/1?_expand=post
要獲得或創(chuàng)建nested resources(默認一層,多層的話,自定義routes)
GET /posts/1/comments
POST /posts/1/comments
Database
GET /db
Homepage
返回默認的index文件,或者./public目錄
GET /
拓展功能
靜態(tài)文件服務器
你也可以用json server來托管你的靜態(tài)HTML,JS和CSS文件。僅僅需要簡單的創(chuàng)建一個./public目錄?;蛘哂?code>--static來指定一個不同的靜態(tài)文件路徑。
mkdir public
echo 'hello world' > public/index.html
json-server db.json
json-server db.json --static ./some-other-dir
改變端口號
你可以改變端口號使用--port
$ json-server --watch db.json --port 3004
從任何地方訪問
你可以使用CORS和JSONP從任何地方訪問你的API。
遠程文件
你可以加載遠程文件
$ json-server http://example.com/file.json
$ json-server http://jsonplaceholder.typicode.com/db
生成隨機數(shù)據(jù)
使用js文件替代json文件,可以動態(tài)生成數(shù)據(jù)。還可以借助其他模塊生成,比如Faker, Casual, Chance or JSON Schema Faker。
// index.js
module.exports = () => {
const data = { users: [] }
// Create 1000 users
for (let i = 0; i < 1000; i++) {
data.users.push({ id: i, name: `user${i}` })
}
return data
}
$ json-server index.js
HTTPS
有很多方式在開發(fā)中使用SSL。一個簡單的方式就是使用hotel.
自定義路由
創(chuàng)建routes.json文件。注意每個路由文件應該以/開頭。
{
"/api/*": "/$1",
"/:resource/:id/show": "/:resource/:id",
"/posts/:category": "/posts?category=:category",
"/articles\\?id=:id": "/posts/:id"
}
啟動json server時加上--routes選項。
json-server db.json --routes routes.json
現(xiàn)在你可以用附加路由訪問資源了。
/api/posts # → /posts
/api/posts/1 # → /posts/1
/posts/1/show # → /posts/1
/posts/javascript # → /posts?category=javascript
/articles?id=1 # → /posts/1
增加中間件
命令行中,你可以使用--middlewares選項。
// hello.js
module.exports = (req, res, next) => {
res.header('X-Hello', 'World')
next()
}
json-server db.json --middlewares ./hello.js
json-server db.json --middlewares ./first.js ./second.js
CLI usage
你可以將設置放在json-server.json配置文件里。
將json server作為一個模塊
在項目中,如何你需要增加認證,驗證或者其他功能,你可以將json server作為一個模塊,合并其他的Express中間件。
一個簡單的例子
// server.js
const jsonServer = require('json-server')
const server = jsonServer.create()
const router = jsonServer.router('db.json')
const middlewares = jsonServer.defaults()
server.use(middlewares)
server.use(router)
server.listen(3003, () => {
console.log('JSON Server is running')
})
$ node server.js
你提供給jsonServer.router方法的路徑,是相對于你的node的。
如果你從另外一個路徑運行上面的代碼,最好用絕對路徑。
const path = require('path')
const router = jsonServer.router(path.join(__dirname, 'db.json'))
對于內(nèi)存數(shù)據(jù)庫,傳遞一個對象給jsonServer.router()。注意,jsonServer.router()可以被用在一個已經(jīng)存在的Express項目中。
自定義路由動態(tài)數(shù)據(jù)的例子
//db.js
let Mock = require('mockjs');
let Random = Mock.Random;
module.exports = function() {
var data = {
news: [],
type:{
"a":"a",
"b":"b",
}
};
var images = [1,2,3].map(x=>Random.image('200x100', Random.color(), Random.word(2,6)));
for (var i = 0; i < 10; 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
}
//server.js
const path = require('path');
const config = require('./config');
const jsonServer = require('json-server');
const rules = require('./routes');
const dbfile = require(config.DB_FILE);
const ip = config.SERVER;
const port = config.PORT;
const db_file = config.DB_FILE;
const server = jsonServer.create();
const router = jsonServer.router(dbfile());
const middlewares = jsonServer.defaults();
server.use(jsonServer.bodyParser);
// Set default middlewares (logger, static, cors and no-cache)
server.use(middlewares);
server.use((req, res, next) => {
res.header('X-Hello', 'World');
next();
})
router.render = (req, res) => {
res.jsonp({
body: res.locals.data,
code: 0
})
}
server.use("/api",router);
server.use(jsonServer.rewriter(rules));
server.use(router);
server.listen({
host: ip,
port: port,
}, function() {
console.log(JSON.stringify(jsonServer));
console.log(`JSON Server is running in http://${ip}:${port}`);
});
//routes.js
module.exports= {
"/api/": "/",
"/:id": "/news/:id",
"/news/show/:id": "/news/:id",
"/topics/:id/show": "/news/:id"
}
添加一個路由輸出query parameters
// Add custom routes before JSON Server router
server.get('/echo', (req, res) => {
res.jsonp(req.query)
})
添加一個時間戳
支持post請求需要使用
bodyParser
// To handle POST, PUT and PATCH you need to use a body-parser
// You can use the one used by JSON Server
server.use(jsonServer.bodyParser)
server.use((req, res, next) => {
if (req.method === 'POST') {
req.body.createdAt = Date.now()
}
// Continue to JSON Server router
next()
})
添加控制
server.use((req, res, next) => {
if (isAuthorized(req)) { // add your authorization logic here
next() // continue to JSON Server router
} else {
res.sendStatus(401)
}
})
修改response數(shù)據(jù)結構
需要override router.render方法。
// In this example, returned resources will be wrapped in a body property
router.render = (req, res) => {
res.jsonp({
body: res.locals.data
})
}
自定義reponse狀態(tài)碼
// In this example we simulate a server side error response
router.render = (req, res) => {
res.status(500).jsonp({
error: "error message here"
})
}
Rewriter例子
添加rewrite rules,使用jsonServer.rewriter():
// Add this before server.use(router)
server.use(jsonServer.rewriter({
'/api/*': '/$1',
'/blog/:resource/:id/show': '/:resource/:id'
}))
Mounting JSON Server on another endpoint example
更改掛載點
掛在/api上
server.use('/api', router)
代碼下載