本地数据接口 —— json-server 从入门到膨胀
如果不想自己在本地搭环境,还可以使用 《前端需要的免费在线api接口》 里推荐的几个线上接口平台,里面包括常用的 json
结构数据和图片。
虽然有线上的免费接口可以测试,但需要自定义接口和数据的时候,还是本地模拟数据比较适合前端开发者。
本文分 入门篇 和 进阶篇。再往下滑一点就能看到全文目录。
入门篇: 5分钟内带你实现 本地环境搭建 和 增删改查 操作,满足入门测试使用。
进阶篇: 主要讲解常用的 查询操作,除此之外还包括 常规配置、静态资源配置 等知识点。这部分有点长,建议收藏。
本文约定
-
本文主要面向的读者是 前端小白,几乎不会涉及到后端知识,所以并不打算讲解
json-server 中间件
的内容。 -
本文讲到的所有知识点都会提供对应的代码展示(会比官方文档详细点)。
-
本文使用
postman
测试,希望能照顾到使用不同工具库做数据请求的读者(我知道还有只懂jQuery
的开发者)。 -
特殊情况会使用
axios
配合演示。
点赞 + 收藏 = 学会了
目录
思维导图.png
入门
json-server简介
Get a full fake REST API with zero coding in less than 30 seconds (seriously)
引用了官方的一句话,大概意思是30秒就能获得一套完整的模拟 REST API 接口。
使用 json-server
需要遵守一定的规范。
-
数据查询要使用
GET
。 -
新增数据要使用
POST
。 -
删除数据要使用
DELETE
。 -
修改数据使用
PUT
和PATCH
。
其他啰嗦的介绍可以打开上面提供的网址看看。
30秒起步
30秒起步分 4 步完成:
-
node
环境安装 -
安装
json-server
-
创建数据库(其实就是一个
json
文件) -
启动服务
1. node 环境安装
json-server
需要通过 npm
下载,npm
依赖在 node
中。
node
常见的安装方法有2种。第一种是官方下载,第二种是使用 nvm
下载。自己选一种就行。
node 官网,点击进入主页下载,下载完狂按“下一步”和“完成”就行了。
注意: node
版本一定要 12
以上。不然会报以下错误:
json-server requires at least version 12 of Node, please upgrade
2. 安装 json-server
可以全局安装,也可以在某项目里安装。这里建议全局安装,因为以后你可能会对 json-server
产生依赖。
全局安装方式:
npm install -g json-server
3. 创建数据库
在你本机创建一个文件夹,然后新建一个 json
文件,再填入数据即可。
建议文件名不要出现中文。
例:
创建 json-server-demo
文件夹,在 json-server-demo
里创建 db.json
文件(这些文件夹和文件名都可以自由命名)。
db.json
文件录入以下数据(数据来自 json-server
官方文档,你也可以使用自己的数据)
{ "posts": [ { "id": 1, "title": "json-server", "author": "typicode" } ], "comments": [ { "id": 1, "body": "some comment", "postId": 1 } ], "profile": { "name": "typicode" } }
4. 启动服务
进入 json-server-demo
目录,打开终端输入以下命令即可
json-server --watch db.json
首页和三个接口都可以直接在浏览器访问,自己打开试试吧。
搞掂!
查(get)
json-server
查询数据需要使用 GET
方法。
入门篇 只写一种查询方法,其他查询操作请往下滑,看 进阶篇。
上一小节创建了3个接口,我们可以直接在浏览器、postman或者自己写JS代码获取数据。
http://localhost:3000/posts
http://localhost:3000/comments
和 http://localhost:3000/profile
两个接口可以自己尝试,这里不再啰嗦。
增(post)
json-server
新增数据需要使用 POST
方法。
例:给
posts
添加一条新的数据。
http://localhost:3000/posts
这里使用 POSt
方法向 /posts
接口传输数据,/posts
原本的数据结构是包含 id、title、author
三个字段,id
默认是自增主键,不传的话会默认增加。
此时打开 db.json
文件看看,可以发现 posts
里多了一条数据。
需要注意的是:
json-server
默认情况下并不会限制你上传的数据格式和类型,所以需要你严格遵循自己设计的数据格式来添加和修改。
删(delete)
json-server
删除数据需要使用 DELETE
方法。
删除的公式是:
http://localhost:3000/{接口名}/{id}
比如现在要删除刚刚上传的那条数据
{ "title": "leihou", "author": "雷猴", "id": 2 }
可以看到刚刚上传的那条数据的 id
为 2
http://localhost:3000/posts/2
此时打开 db.json
就会发现刚刚删除的那条数据已经没了。
需要注意的是: 删除成功
Status
会返回200
;如果删除的数据不存在会返回404
。
我用 axios
模拟了一下。
删除成功返回的结果:
删除失败返回的结果:
改(put 和 patch)
修改数据分为2个方法:
-
put
:覆盖 -
patch
:更新
公式如下所示:
http://localhost:3000/posts/{id}
覆盖(put)
例:把
id
为1
的数据改成{ "title": "leihou", "author": "雷猴" }
此时打开 db.json
就可以看到 id
为 1
的数据已经发生变化。
注意:原本的数据包含
title
和author
,使用put
时必须把这两个字段都写上,不然会删掉没传的字段。这就是 “覆盖” 的意思。
例如:
此时查看 db.json
会发现数据被覆盖了
更新(patch)
先还原一下数据,改成如下图所示:
此时有 title
和 author
字段。
例:使用 patch
方法把 id
为 1
的数据 title
字段的值更改成 hello
。
正在上传…重新上传取消
13.png
打开 db.json
文件查看一下,会发现只改了 id
为 1
的 title
值,并没有删掉 author
这个字段的数据。
正在上传…重新上传取消
进阶
启动参数
我们之前使用 json-server --watch db.json
这条命令启动了接口项目,其中 json-server
是服务启动的命令,--watch
是参数,db.json
是目标文件。
使用下面这条命令可以 查看配置项:
json-server --help # 或使用简写方式 json-server -h
参数 | 简写 | 说明 |
---|---|---|
--config | -c | 指定配置文件 |
--port | -p | 端口号 |
--host | -H | 主机地址 |
--watch | -w | 监听文件 |
--routes | -r | 指定路由文件 |
--middlewares | -m | 指定中间件 |
--static | -s | 设置静态文件 |
--read-only | --ro | 只读 |
--no-cors | --nc | 禁用跨源资源共享 |
--no-gzip | --ng | 禁止GZIP |
--snapshots | -S | 设置快照目录 |
--delay | -d | 设置反馈延时(ms) |
--id | -i | 设置数据的id属性(e.g. _id) |
--foreignKeySuffix | --fks | 设置外键后缀(如post_id中的_id) |
--quiet | -q | 禁止输出日志消息 |
--help | -h | 显示帮助信息 |
--version | -v | 显示版本号 |
配置
使用 json-server --help
可以查看到所有配置项。接下来我演示几个常见的配置操作。
端口
使用 -p
或者 --port
配置端口号,例如配置 6666
端口
json-server -p 6666 db.json
启动后
\{^_^}/ hi! Loading db.json Done Resources http://localhost:6666/posts http://localhost:6666/comments http://localhost:6666/profile Home http://localhost:6666
主机地址
json-server --host 0.0.0.0 db.json
这里设置了 0.0.0.0
,之后通过本机 IP
来访问即可。同一个局域网内的其他设备也可以通过这个地址来访问。
查询的常用操作
查询是日常项目中接触最多的操作,所以查询是重点。
普通查询
用 30秒起步 的那份数据。
查询
/posts
所有数据
http://0.0.0.0:3000/posts
查询
/comments
所有数据
http://localhost:3000/comments
查询
/profile
所有数据
http://localhost:3000/profile
id查询
将 db.json
的内容修改一下。
{ "posts": [ { "id": 1, "title": "文章111", "author": "张三" }, { "id": 2, "title": "文章222", "author": "李四" } ] }
此时只有 posts
接口,里面有2条数据,id
分别为 1
和 2
。
查询的公式是:
http://localhost:3000/posts/{id}
查询
id
为2
的数据
http://localhost:3000/posts/2
条件查询
准备以下数据。
{
"posts": [
{
"id": 1,
"title": "文章111",
"author": "张三"
},
{
"id": 2,
"title": "文章222",
"author": "李四"
},
{
"id": 3,
"title": "文章333",
"author": "张三"
}
]
}
可以看到里面有 2条张三
的数据,1条李四
的数据。
单一条件查询
查找 author
为 张三
的所有数据。
查询
author
是张三
的数据
http://localhost:3000/posts?author=张三
在 http://localhost:3000/posts
后面加一个 ?
,然后写上筛选条件即可。
多条件查询(且)
上面的数据,有2条张三的。
这次要筛选的是
author = 张三
且title = 文章333
的数据
http://localhost:3000/posts?author=张三&title=文章333
符合条件赛选的时候,使用 &
号添加条件。
多条件查询(或)
这次要筛选的是
title = 222
和title = 333
这两条数据出来。
http://localhost:3000/posts?title=文章222&title=文章333
重复使用 title
,会把符合条件的都筛查出来。
当然,我们还可以使用 模糊查询 来达到类似的效果,稍后会讲到。
深度属性查询
这里需要准备另一份数据才能展示这个知识点。
数据内容如下
{ "posts": [ { "id": 1, "title": "文章111", "authorInfo": { "name": "张三", "age": 20 } }, { "id": 2, "title": "文章222", "authorInfo": { "name": "李四", "age": 24 } } ] }
可以看到 authorInfo
里面还有子属性。
查询
authorInfo.name = 张三
的数据。
http://localhost:3000/posts?authorInfo.name=张三
这里需要使用 .
的方式来访问子级数据,有点像 js
用点语法访问对象属性那样。
工作中我遇到这样的接口不多。
分页查询
使用 _page
和 _limit
(可选) 对数据进行分页。需要注意,_page
和 _limit
前面都要有下划线。
-
_page
:页码 -
_limit
:每页的数据量
修改 db.json
里的数据方便测试分页功能,如下所示
{ "comments": [ { "id": 1, "body": "some comment 1", "postId": 1 }, { "id": 2, "body": "some comment 2", "postId": 1 }, { "id": 3, "body": "some comment 3", "postId": 2 }, { "id": 4, "body": "some comment 4", "postId": 3 }, { "id": 5, "body": "some comment 5", "postId": 1 }, { "id": 6, "body": "some comment 6", "postId": 3 }, { "id": 7, "body": "some comment 7", "postId": 3 }, { "id": 8, "body": "some comment 8", "postId": 1 }, { "id": 9, "body": "some comment 9", "postId": 2 }, { "id": 10, "body": "some comment 10", "postId": 2 }, { "id": 11, "body": "some comment 11", "postId": 3 }, { "id": 12, "body": "some comment 11", "postId": 1 } ] }
准备了12条数据。
需要获取第2页的数据,每页3条:
http://localhost:3000/comments?_page=2&_limit=3
除了要返回的数据外,还会在 Headers
里返回 总数;第一个、前一个、下一个、最后一个的链接。我用 axios
发个请求演示一下。
axios.get('http://localhost:3000/comments', { params: { _page: 2, _limit: 3 } }) .then(res => { console.log(res) }) .catch(err => { console.error(err) })
返回结果如下所示
x-total-count
存放总数。
link
字段里存放的是 第一个、前一个、下一个、最后一个 的链接地址
" <http://localhost:3000/comments?_page=1&_limit=3>; rel=\"first\", <http://localhost:3000/comments?_page=1&_limit=3>; rel=\"prev\", <http://localhost:3000/comments?_page=3&_limit=3>; rel=\"next\", <http://localhost:3000/comments?_page=4&_limit=3>; rel=\"last\" "
排序查询
需要添加 排序的标记 ( _sort
),然后设置 排序规则 ( _order
)。
其中,排序规则有 升序 ( asc
) 和 降序 ( desc
) 。
http://localhost:3000/{接口名}?_sort=要排序的字段名&_order=排序规则
以这份数据为例:
{ "comments": [ { "id": 11, "body": "some comment 1", "postId": 1 }, { "id": 2, "body": "some comment 2", "postId": 1 }, { "id": 3, "body": "some comment 3", "postId": 2 }, { "id": 10, "body": "some comment 4", "postId": 3 }, { "id": 7, "body": "some comment 5", "postId": 1 }, { "id": 6, "body": "some comment 6", "postId": 3 }, { "id": 5, "body": "some comment 7", "postId": 3 }, { "id": 8, "body": "some comment 8", "postId": 1 }, { "id": 9, "body": "some comment 9", "postId": 2 }, { "id": 4, "body": "some comment 10", "postId": 2 }, { "id": 1, "body": "some comment 11", "postId": 3 }, { "id": 12, "body": "some comment 11", "postId": 1 } ] }
id
的排序是乱的,如果使用普通的方式请求回来的数据是原模原样返回的。
升序
以
id
为参考字段进行升序排列返回给客户端。
http://localhost:3000/comments?_sort=id 或 http://localhost:3000/comments?_sort=id&_order=asc
返回的结果就会以 id
为参考字段升序排好。
普通升序排列的话,_order=asc
可以不传。只需指定 参考字段 ( _sort
) 即可。
降序
降序必须填好
_order=desc
。
http://localhost:3000/comments?_sort=id&_order=desc
多字段排序
这次的需求是:
-
首先按
postId
升序排列 -
在
1
的基础上再对id
进行倒序排列
多个字段用
,
分格。
http://localhost:3000/comments?_sort=postId,id&_order=asc,desc
返回结果:
{ "comments": [ { "id": 12, "body": "some comment 11", "postId": 1 }, { "id": 11, "body": "some comment 1", "postId": 1 }, { "id": 8, "body": "some comment 8", "postId": 1 }, { "id": 7, "body": "some comment 5", "postId": 1 }, { "id": 2, "body": "some comment 2", "postId": 1 }, { "id": 9, "body": "some comment 9", "postId": 2 }, { "id": 4, "body": "some comment 10", "postId": 2 }, { "id": 3, "body": "some comment 3", "postId": 2 }, { "id": 10, "body": "some comment 4", "postId": 3 }, { "id": 6, "body": "some comment 6", "postId": 3 }, { "id": 5, "body": "some comment 7", "postId": 3 }, { "id": 1, "body": "some comment 11", "postId": 3 } ] }
符合需求。
切片查询
切片的意思是指定 头 和 尾 ;也可以指定 头 和 片段长度 。
用到的关键字有:
-
_start
:开始位置(下标,从0开始) -
_end
:结束位置 -
_limit
:片段长度
总数 会放在 headers
里。
以这份数据为例
{ "comments": [ { "id": 1, "body": "some comment 1", "postId": 1 }, { "id": 2, "body": "some comment 2", "postId": 1 }, { "id": 3, "body": "some comment 3", "postId": 2 }, { "id": 4, "body": "some comment 4", "postId": 3 }, { "id": 5, "body": "some comment 5", "postId": 1 }, { "id": 6, "body": "some comment 6", "postId": 3 }, { "id": 7, "body": "some comment 7", "postId": 3 }, { "id": 8, "body": "some comment 8", "postId": 1 }, { "id": 9, "body": "some comment 9", "postId": 2 }, { "id": 10, "body": "some comment 10", "postId": 2 }, { "id": 11, "body": "some comment 11", "postId": 3 }, { "id": 12, "body": "some comment 11", "postId": 1 } ] }
需求:返回下标从
2-6
的数据
使用 _start
和 _end
的方式
http://localhost:3000/comments?_start=2&_end=6
使用 _start
和 _limit
的方式
http://localhost:3000/comments?_start=2&_limit=4
范围查询
范围查询包括 大于等于、小于等于、不等于 三种情况。
大于等于 _get
大于等于 使用的关键字是 _get
。注意,前面有个下划线的。
需求:查询
comments
接口id
大于等于4
的数据
http://localhost:3000/comments?id_gte=4
小于等于 _lte
需求:查询
comments
接口id
小于等于4
的数据
http://localhost:3000/comments?id_lte=4
联合一起使用
需求:查询
comments
接口id
大于等于4
且 小于等于6
的数据
http://localhost:3000/comments?id_gte=4&id_lte=6
不等于 _ne
需求:查询
comments
接口id
不等于2
的数据
http://localhost:3000/comments?id_ne=2
模糊查询
模糊查询的关键字是 _like
。
需求:查询
comments
接口body
包含1
的数据
全文查询
全文查询的关键字是 q
准备以下数据比较好演示
{ "authors": [ { "id": 1, "name": "zhangsan", "age": 18}, { "id": 2, "name": "lisi", "age": 21}, { "id": 3, "name": "wangwu", "age": 24} ] }
查询所有字段中包含
2
的数据出来
http://localhost:3000/authors?q=2
因为 id
为 3
的那条数据里 age
是 24
,也算是包含了 2
。
外键关联查询
外键查询需要 2个接口 关联查询。
准备以下数据方便演示
{ "posts": [ { "id": 1, "title": "文章111", "author": "张三" }, { "id": 2, "title": "文章222", "author": "李四" } ], "comments": [ { "id": 1, "body": "some comment 1", "postId": 1 }, { "id": 2, "body": "some comment 2", "postId": 1 }, { "id": 3, "body": "some comment 3", "postId": 2 } ] }
posts
里有2条数据。
comments
里有3条数据,其中每条数据都有一个 postId
,是对应 posts
每条数据的 id
。
需求:查询
posts
里id
为1
的所有comments
内容
http://localhost:3000/posts/1/comments
关系拼装
关系拼装可以把关联的2个接口的数据拼接起来并返回。
其中有2种查询关系:
-
包含子资源
_embed
-
包含父资源
_expand
准备以下数据方便演示
{ "posts": [ { "id": 1, "title": "文章111", "author": "张三" }, { "id": 2, "title": "文章222", "author": "李四" } ], "comments": [ { "id": 1, "body": "some comment 1", "postId": 1 }, { "id": 2, "body": "some comment 2", "postId": 1 }, { "id": 3, "body": "some comment 3", "postId": 2 } ] }
包含子资源 _embed
http://localhost:3000/posts?_embed=comments
还可以拼接多个条件。
需求:在
comments
里,把posts
里id
为2
的数据找出来并拼接起来
http://localhost:3000/posts/2?_embed=comments
包含父资源 _expand
http://localhost:3000/comments?_expand=post
配置路由
有时候我们的 api地址
可能不像上面所有案例中那么简单,此时就可以使用 自定义路由 的方法来模拟。
比如模拟下面这个接口:
http://localhost:3000/api/users/1
实现的步骤如下所示:
-
创建
routes.json
文件(也可以不叫这个名字) -
启动服务时使用
--routes
参数
1、创建 routes.json
,并输入以下内容。
{ "/api/*": "/$1" }
2、启动服务
json-server db.json --routes routes.json
3、访问
http://localhost:3000/api/posts
静态资源
静态资源包含 html
、css
、js
、图片、视频等资源。
配置
配置方式分2种:
-
默认配置
-
指定资源位置
默认配置
需要在根目录下创建 public
文件夹,里面放入 html
等文件。
然后在浏览器访问一下 http://localhost:3000/
你也可以加入自己的 css
和 js
进行设计交互。
指定资源位置
json-server
配资静态资源的默认方式是在根目录下创建 public
文件夹,然后里面放入静态资源。
但如果你不想使用 public
作为静态资源的文件夹,也可以自己起过另一个名字,然后在启动环境时使用 --static
来指定目标目录就行了。
比如我创建了一个 some-other-dir
作为静态资源的目录,使用以下命令指定以下即可。
json-server db.json --static ./some-other-dir
多媒体资源
除了放 html
、css
和 js
资源外,还可以放图片和视频。
我以图片为例,我在 public
目录下添加一个图片。
直接在 http://localhost:3000/
后面跟着 图片文件名
即可。
其他
生成动态数据
如果我们要模拟100条数据,甚至更多的话,创建 json
文件然后一条一条录入的方式真的很不合时。
此时我们可以使用 js
通过循环的方式来实现数据创建。
1、首先在根目录下创建一个 db.js
的文件。
2、输入一下内容
module.exports = () => { const data = { users: [] } // 创建 100 个 users for (let i = 0; i < 100; i++) { data.users.push({ id: i, name: `user${i}` }) } return data }
3、运行 js
文件
json-server db.js
4、查询一下
http://localhost:3000/users
100条数据就直接生成了。
需要什么字段可以自己在 js
文件里配置。
查询整个数据库
访问以下地址可以获得整个数据库的数据。
http://localhost:3000/db
远程模式
如果想使用互联网上的数据,也可以直接运行 json-server
然后加上远端的地址即可。
json-server http://jsonplaceholder.typicode.com/db