Fake JSON Server
Fake JSON Server
https://github.com/ttu/dotnet-fake-json-server
Fake JSON Server 是 Fake REST API,可以作为原型来模拟后端 API,活着临时用于 CRUD 的后端。Fake JSON Server 可以作为体验版的 GraphQL 查询和变化支持。
- 不需要定义资源类型,直接使用动态类型
- 不需要定义路由,路由动态处理
- 不需要数据库,数据保存在单个 JSON 文件中
- 不需要准备,只需要启动该服务器,API 就可以用于任何数据
为什么要使用它来替代其他的 Fake 服务器?
- 使用最佳实践来构建 API,当构建你的 API 的时候,可以作为参考时限。
- 可以运行在 Windows、Linux 和 macOS 平台上,而不需要任何的安装或者预先的执行,或者 Docker 环境
- 功能列表如下
功能
- 支持的 HTTP 方法
- 所有的 CRUD 操作 (GET、PUT、POST、PATCH、DELETE)
- 用来提取资源的方法 (HEAD、OPTIONS)
- 针对长时间的更新操作与查询提供的异步版本
- REST API 遵循多个来源的最佳实践
- 使用正确的状态吗、头部等等
- 由于各种最佳实践都有一点区别,这些冲突的地方基于你的观点
- Token、Basic 和 API Key 认证方式支持
- WebSocket 更新提示
- 针对查询的延迟与错误的仿真
- 静态文件支持
- Swagger 支持
- CORS
- 内容协商 (输出格式:JSON、CSV 与 XML)
- 使用 ETag 缓存并避免空中碰撞
- 可配置的定制化响应转换
- 体验版的 GraphQL 查询与修改支持
开发
- 使用 .NET 5
- 使用 JSON Flat File Data Store 来存储数据
- 可以安装微 dotnet 全局工具使用
- 可以不安装 .NET 就使用
- 使用 Docker
- 编译微自包含应用
目录
入门
使用 .NET CLI 启动
# Get source code from GitHub
$ git clone https://github.com/ttu/dotnet-fake-json-server.git
$ cd dotnet-fake-json-server/FakeServer
$ dotnet run
使用预先定义的数据文件和 url 启动服务器 ( 参数 )
# Optional arguments:
# --file <FILE> Data store's JSON file (default datastore.json)
# --urls <URL> Server url (default http://localhost:57602)
# --serve <PATH> Serve static files (default wwwroot)
# --version Prints the version of the app
$ dotnet run --file data.json --urls http://localhost:57602
安装为 .NET 全局工具
本服务器可以安装成 dotnet 全局工具。设置并保存文件到 %USERPROFILE%.dotnet\tools (Windows), $HOME/.dotnet/tools (Linux/macOS).。作为默认数据存储的 JSON 文件将被创建到执行目录中。
# install as a global tool
$ dotnet tool install --global FakeServer
# Example: Start server
$ fake-server --file data.json --urls http://localhost:57602
# Update to the newest version
$ dotnet tool update --global FakeServer
Docker
如果你的机器没有安装 .NET,可以通过 Docker 来使用。
# Get source code from GitHub
$ git clone https://github.com/ttu/dotnet-fake-json-server.git
$ cd dotnet-fake-json-server
$ docker build -t fakeapi .
# Run in foreground
$ docker run -it -p 57602:57602 --name fakeapi fakeapi
# Run in detached mode (run in background)
$ docker run -it -d -p 57602:57602 --name fakeapi fakeapi
# Start stopped container (remove -a to run in background)
$ docker start -a fakeapi
将 JSON 文件复制到/复制出 Docker 容器,文件名为 datastore.json。
# Copy file from host to container
$ docker cp datastore.json fakeapi:/app/datastore.json
# Copy file from container to host
$ docker cp fakeapi:/app/datastore.json datastore.json
111
自包含应用
作为自包含的应用,其中包含了 Fake JSON Server 本身,.NET 运行时,和所有需要的第三方依赖。不需要安装,也不需要预先设置。
- 访问 最新发布版本
- 根据你的操作系统下载对应版本
- 解压并执行
例如下载 macOS 的 0.11.0 版本
$ mkdir FakeServer && cd FakeServer
$ wget https://github.com/ttu/dotnet-fake-json-server/releases/download/0.11.0/fakeserver-osx-x64.tar.gz
$ tar -zxvf fakeserver-osx-x64.tar.gz
$ chmod +x FakeServer
$ ./FakeServer
静态文件支持
Fake Server 支持静态文件,静态文件的位置可以使用绝对路径,也可以使用相对于当前位置的相对路径。
$ dotnet run -s/--serve [fullpath/relative path]
# e.g.
$ dotnet run -s build
# Use Fake Server as a global tool
$ fake-server -s/--serve [fullpath/relative path]]
# e.g.
$ fake-server --serve c:\temp\react_app\build
$ fake-server --serve /home/user/app/dist
$ fake-server --serve ./build
当使用静态文件支持的时候,它假设用户服务于单页应用,而 REST API 将不再工作。如果还需要 API 支持,启动 Fake Server 的另外一个实例。
快速示例
# List collections (should be empty, if data.json didn't exist before)
$ curl http://localhost:57602/api
# Insert new user
$ curl -H "Content-type: application/json" -X POST -d '{ "name": "Phil", "age": 20, "location": "NY" }' http://localhost:57602/api/users/
# Insert another user
$ curl -H "Content-type: application/json" -X POST -d '{ "name": "James", "age": 40, "location": "SF" }' http://localhost:57602/api/users/
# List users
$ curl http://localhost:57602/api/users
# List users from NY
$ curl http://localhost:57602/api/users?location=NY
# Get User with Id 1
$ curl http://localhost:57602/api/users/1
...
# Add users to data.json manually
# Get all users
$ curl http://localhost:57602/api/users/
...
# Or open url http://localhost:57602/swagger/ with browser and use Swagger
示例项目
Redux TodoMVC 示例,使用 Fake JSON Server 作为后端服务。
特性
认证 Authentication
Fake REST API 支持 Token 和 BASIC 认证。
可以通过将 appsettings.json
中的 Authenticaion
中的 Enabled
设置为 false 来禁用。AuthenticationType
的类型可以是:
- token
- basic
- apikey
将支持的用户名和口令添加到 Users
仿数组中,而 API Key 则使用 ApiKey
属性进行设置。
"Authentication": {
"Enabled": true,
"AuthenticationType": "token",
"Users": [
{ "Username": "admin", "Password": "root" }
],
"ApiKey": "abcd1234"
}
Token 认证
API 服务器提供了用来生成访问令牌的端点 /token
。端点支持 content-type: multipart/form-data
和 content-type: application/json
。使用的用户名和密码必须来自 Users
中的 username
和 password
字段。
获取 Token
# content-type: multipart/form-data
$ curl -X POST -H 'content-type: multipart/form-data' -F username=admin -F password=root http://localhost:57602/token
# content-type: application/json
$ curl -X POST -H 'content-type: application/json' -d '{ "username": "admin", "password": "root" }' http://localhost:57602/token
令牌还可以使用 Client Credentials
认证流方式来获得。
$ curl -X POST -d "grant_type=client_credentials&client_id=admin&client_secret=root" http://localhost:57602/token
将获得的令牌添加到 Authorization 请求头中
$ curl -H 'Authorization: Bearer [TOKEN]' http://localhost:57602/api
Token 认证还提供了登出功能支持。默认令牌是不支持无效的,所以,通过 logout 来通过将 token 加入到黑名单。
$ curl -X POST -d '' -H 'Authorization: Bearer [TOKEN]' http://localhost:57602/logout
该实现非常类似于 SimpleTokenProvider,详细内容可以参考 GitHub 和 StormPath's blog post.
BASIC 认证
不建议在产品环境中使用 BASIC 认证,Base64 编码是可以逆向解密的。
将用户名和密码使用 Base64 编码之后,添加到 Authorization 请求头,例如:'Authorization: Basic YWRtaW46cm9vdA=='
$ curl -u admin:root http://localhost:57602/api
# -u argument creates Authorization header with encoded username and password
$ curl -H 'Authorization: Basic YWRtaW46cm9vdA==' http://localhost:57602/api
API Key 认证
API Key 使用 X-API-KEY
请求头,例如 X-API-KEY: abcd1234
.
$ curl -H 'X-API-KEY: abcd1234' http://localhost:57602/api
WebSockets 支持
API 将会使用 Web Socket 发送最后更新的方法 (POST, PUT, PATCH, DELETE), Path、collection 和可选的条目 id
{ "method": "PATCH", "path": "/api/users/2", "collection": "users", "itemId": 2 }
wwwroot/index.html 中包含一个 WebSocket 的示例。
CORS
CORS 已经被弃用,并全面支持。
静态文件
GET /
返回来自 wwwroot 或者自定义的位置 的静态文件。默认文件名为 index.html。
Swagger
Swagger 配置在端点 /swagger 下。
使用 ETag 实现缓存和避免空中碰撞
缓存可以禁用:
"Caching": {
"ETag": {
"Enabled": true
}
}
如果弃用了缓存,响应头中会添加 ETag 响应头。
$ curl -v 'http://localhost:57602/api/users?age=40'
200 OK
Headers:
ETag: "5yZCXmjhk5ozJyTK4-OJkkd_X18"
缓存不会改变的资源
如果请求包含 If-None-Match 请求头,该请求头的值将与响应体的内容相比较,如果该值与响应体的校验和匹配,那么会返回 304 Not Modified
。
$ curl -H "If-None-Match: \"5yZCXmjhk5ozJyTK4-OJkkd_X18\"" 'http://localhost:57602/api/users?age=40'
避免空中碰撞
如果 PUT 请求中包含 If-Match 请求头,其值将与被更新的项目相比较。如果该值匹配将要被更新的项目的校验和,那么将返回 412 Precondition Failed
内容协商
客户端可以通过 Accept 请求头来决定期望返回的表示类型。默认返回 JSON 格式 ( text/json,application/json)。
支持的协商类型是 JSON、CSV 和 XML
text/json
application/json
text/csv
text/xml
application/xml
获取 CSV 格式的所有用户
$ curl -H "Accept: text/csv" http://localhost:57603/api/users
如果提供的内容类型不被支持,将返回 406 Not Acceptable
路由、功能和示例
GET /
POST /token
POST /logout
POST /admin/reload
GET /api
HEAD /api
GET /api/{collection/object}
HEAD /api/{collection/object}
POST /api/{collection}
GET /api/{collection}/{id}
HEAD /api/{collection}/{id}
PUT /api/{collection}/{id}
PATCH /api/{collection}/{id}
DELETE /api/{collection}/{id}
PUT /api/{object}
PATCH /api/{object}
DELETE /api/{object}
OPTIONS /api/*
GET /async/queue/{id}
DELETE /async/queue/{id}
POST /async/{collection}
PUT /async/{collection}/{id}
PATCH /async/{collection}/{id}
DELETE /async/{collection}/{id}
OPTIONS /async/*
POST /graphql
集合与对象
Fake JSON Server 被设计作为原型,所以默认支持的仅有资源是集合。
如果该 JSON 文件只有单个对象在根上,那么作为单个对象使用。
{
"collection": [],
"object": {}
}
路由
动态路由使用条目集合的名称和 id:api/{collection}/{id}
。所有下面的示例都使用 users 作为集合名称。
如果由于某种原因,需要修改 /api 或者 /async ,通过 Config.cs 中的 ApiRoute 或者 AsyncRoute 来实现。
public class Config
{
public const string ApiRoute = "api";
public const string AsyncRoute = "async";
public const string GraphQLRoute = "graphql";
public const string TokenRoute = "token";
public const string TokenLogoutRoute = "logout";
}
例如,如果不希望使用 api 前缀,那么可以通过 ApiRoute 来删除 api 前缀。
public const string ApiRoute = "";
使用
# Query with default route
$ curl 'http://localhost:57602/api/users?skip=5&take=20'
# Query with updated route
$ curl 'http://localhost:57602/users?skip=5&take=20'
标识
id
用来作为标识字段,默认的 id 字段类型为整数,POST 操作总是使用整数作为 id 的类型。
"users":[
{ "id": 1 }
],
"sensors": [
{ "id": "E:52:F7:B3:65:CC" }
]
如果使用字符串作为标识类型,那么条目必须使用 PUT 插入,并且 appsetting.json 中的 UpsertOnPut 必须设置为 true。
返回码
异步操作遵循 REST 菜谱手册。更新将返回 202,使用 Location 响应头来将条目排入队列中。队列在操作处理中将返回 200,当 job 完成,而 Location 头对新条目变化的时候,返回 303
方法的返回码遵循 REST API 教程