在开发过程中,接口多半是滞后于页面开发的。利用JSON Server快速搭建模拟返回REST风格的后台数据,保证前后端开发的分离。前后端开发只要设定好接口以及数据的定义,剩下的就可以各自开发,最后集成测试。
JSON Server 作为工具,基于Express开发,而且它足够简单,写少量数据,即可使用,支持CORS和JSONP跨域请求,支持GET, POST, PUT, PATCH 和 DELETE 方法,更提供了一系列的查询方法,如limit,order等
安装
npm install json-server -g
全局安装,可以在命令行下独立执行。安装完成后可以用 json-server -h
命令检查是否安装成功。
json-server [options]
启动
创建一个目录server,在该目录下创建一个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目录下执行
json-server db.json -p 3003
打开浏览器,http://localhost:3003
,查看页面。如果要监控json文件的变化,启动的时候加上参数--watch
。
支持的方法
以APIhttp://localhost:3003/list
为例
- GET /list 获取列表
- GET /list/1 获取id=1的数据
- POST /list 创建一个项目
- PUT /list/1 更新一个id为1的数据
- PATCH /list/1 部分更新id为1的数据
- DELETE /list/1 删除id为1的数据
对于对象,例如http://localhost:3003/user
,地址是相同的。
- GET /user
- POST /user
- PUT /user
- PATCH /user
- 当你发送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
来对返回数据定制(不设置默认返回10条)。
在返回的header中,有一个属性Link
,里面会有first, prev, next and last links。
header中还有一个属性X-Total-Count
,用来存储满足条件的数据的条数。
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里面),就像数据的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
关联子资源, 添加_embed
GET /posts?_embed=comments
GET /posts/1?_embed=comments
包含父资源, 添加_expand
GET /comments?_expand=post
GET /comments/1?_expand=post
要获得或创建nested resources(默认一层,多层的话,自定义routes)
GET /posts/1/comments
POST /posts/1/comments
Database
GET /db
Homepage
返回默认的index文件,或者./public目录
GET /
拓展功能
静态文件服务器
你也可以用json server来托管你的静态HTML,JS和CSS文件。仅仅需要简单的创建一个./public
目录。或者用--static
来指定一个不同的静态文件路径。
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
生成随机数据
使用js文件替代json文件,可以动态生成数据。还可以借助其他模块生成,比如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
有很多方式在开发中使用SSL。一个简单的方式就是使用hotel.
自定义路由
创建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
现在你可以用附加路由访问资源了。
/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'))
对于内存数据库,传递一个对象给jsonServer.router()
。注意,jsonServer.router()
可以被用在一个已经存在的Express项目中。
自定义路由动态数据的例子
//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数据结构
需要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状态码
// 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)
代码下载
https://github.com/fujusong/JSON-Server-starter.git