JSON Server在快速开发过程中的使用

在开发过程中,接口多半是滞后于页面开发的。利用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] <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]

启动

创建一个目录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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容