本文档是设备管理系统第二版接口开发的设计原则,我们还在不断完善它。
设备管理系统是一套可管理设备的短租和长租业务的系统,具有设备信息录入、设备租赁、订单管理、消息提醒等功能。我们提供一个 REST 风格的 API,它的设计参考了best-practices-for-a-pragmatic-restful-api。
我们的 API 使用面向资源的 URLs,同时较好地利用了 HTTP 本身的一些特征,如 HTTP 动词、HTTP 响应状态码。所有请求和响应的消息体都是 JSON 格式,包括错误响应。任何 HTTP 客户端(浏览器也不例外)都可以用来与 API 进行通信。
我们认为 API 是开发者的用户界面,因此,我们也尽最大努力保证 API 能够方便地通过浏览器直接就可以访问。
内部使用的接口,不需要认证即可调用。
API 的基础地址是 http://10.20.17.211:8008/v2,地址中的 v2 标识当前接口的版本,调用时请替换成实际的版本。
所有 POST, PUT, PATCH 请求所发送的内容都必须是 JSON 格式,并且消息头中必须设置 Content-Type 为 application/json
,否则 API 会返回一个 415 Unsupported Media Type
状态码。
$ curl http://10.20.17.211:8008/v1/devices/136 \
-X PATCH \
-H 'Content-Type: application/json' \
-d '{"content":"this is new content"}'
我们使用标准的 HTTP 动词来表示一个请求的意图:
GET
(选择):从服务器上获取一个具体的资源或者一个资源列表。POST
(创建): 在服务器上创建一个新的资源。PUT
(更新):以整体的方式更新服务器上的一个资源。PATCH
(更新):只更新服务器上一个资源的一个属性。DELETE
(删除):删除服务器上的一个资源。所有响应的内容都是 JSON 的格式。
单个资源时返回 JSON 对象:
{
"field1": "value",
"field2": true,
"field3": []
}
资源列表时返回 JSON 对象,数据会被放在了 items
对象数组中,total_count
是总记录数:
{
"total_count": 135,
"items": [
{
"field1": "value",
"field2": true,
"field3": []
},
{
"field1": "another value",
"field2": false,
"field3": []
}
]
}
如果字段是字符型,使用空字符串(”“)而不是null来表示该字段的值为空。如果该字段是数组,则使用 [] 表示空数组。
我们使用HTTP状态码来表示一个请求成功或失败。
成功状态码:
200 OK
- [GET]:服务器成功返回用户请求的数据201 Created
- [POST/PUT/PATCH]:用户新建或修改数据成功204 No Content
- [DELETE]:用户删除数据成功错误状态码:
400 Bad Request
- [POST/PUT/PATCH]:无法解析用户提交的数据(非JSON格式的数据或JSON数据解析失败),服务器什么也没做404 Not Found
- [*]:用户请求或操作一个不存在的资源或集合,服务器什么也没做415 Unsupported Media Type
- [POST/PUT/PATCH] 当请求头中缺少 Content-Type: application/json
时,将返回此错误422 Unprocesable entity
- [POST/PUT/PATCH] 当用户修改或创建一个资源时,发生一个验证错误,服务器什么也没有做500 Internal Server Error
- [*]:服务器发生内部错误,用户将无法判断发出的请求是否成功400,404,500 系列的错误,响应内容是一个 JSON 对象,并且响应头的 Content-Type 为 application/json。
400 错误
{
"code": "10005",
"message": "无法解析你所提交的数据"
}
404 错误,有以下三种可能的返回:
接口不存在时
{
"code": "10020",
"message": "你所请求的接口不存在"
}
请求的单个资源不存在时
{
"code": "20104",
"message": "你所请求的设备不存在"
}
请求的资源列表不存在时
{
"code": "10010",
"message": "没有任何数据"
}
415 错误
{
"code": "10011",
"message": "请求类型错误"
}
500 错误
{
"code": "10001",
"message": "对不起,服务器发生内部错误,无法得知请求是否成功"
}
code
是全局唯一的错误代码,可以查看错误代码表,查询所对应的错误的详细含义。
POST,PUT,PATHCH 请求发生验证错误时,将会返回 422 Unprocessable Entry
状态码。响应内容中将是 JSON 格式的错误信息数组。
{
"code" : 10006,
"message" : "数据验证错误",
"errors" : [
{
"code" : 21102,
"field" : "meb_name",
"message" : "预订人姓名不能为空"
},
{
"code" : 21106,
"field" : "meb_mobile",
"message" : "预定人手机号的格式不对"
}
]
}
许多接口的除了返回请求资源自身外,还支持返回与此资源相关的资源,这样可以尽量减少API 调用的次数。
使用一个 embed
查询参数来实现这一功能。返回多个相关资源时,请用逗号隔开。
GET /inn/100/devices?embed=images,attributes
响应内容
[
{
"device_id": "156",
"inn_id": "100",
"cat_id": "8",
"name": "浪漫满屋主题公寓",
"images": [
{
"img_id": "29",
"device_id": "156",
"img_url": "http://img0.bdstatic.com/img/image/shouye/xinshouye/sheji206.jpg"
}
],
"attributes": [
{
"id": "22",
"device_id": "156",
"attr_id": "899",
"attr_value": "有空调,电冰箱"
}
]
... other device fields ...
}
]
并非所有接口使用 embed
参数都有效,这与资源本身是否存在相关数据也有关。接口文档会对每个接口是否支持 embed
参数进行说明。
在请求接口返回多条数据时,我们默认将显示前15条数据。当然你可以使用 per_page
和 page
来控制数据的返回。
GET /inn/100/devices?per_page=15&page=2
为了满足部分接口需要一次性获取所有数据的要求,我们特意增加了 all_pages
参数,添加参数 all_pages=true
即可返回该接口的所有数据。当然,为避免服务器压力过大,该参数应该尽量少用。
GET /inn/100/devices?all_pages=true
all_pages
的优先级高于 per_page
和 page
参数,如果同时存在三个参数,只会识别 all_pages
而忽略其他的分页参数。
对于接口返回的结果,有时候需要进行筛选。你可以使用字段名作为筛选的参数,比如说你希望获取ID为100这个分店所有已取消的订单,即可使用
GET /inn/100/orders?state=canceled
有些接口对于返回结果需要进行排序,可以使用 sort
参数。排序参数采取逗号分隔的形式,每一个字段前都可能有一个负号 -
来表示按降序排序。并不是所有字段都可以进行排序,接口文档将会列出每个接口可进行排序的字段。
GET /inn/100/devices?sort=-create_time,name
对于调用接口返回的错误信息,我们将提供中英两种语言的选择。只需要在请求中设置 Accept-Language
报头即可。Accept-Language: zh-cn
表示希望返回中文信息,Accept-Language: en-us
表示希望返回英文信息,默认返回中文信息。
英文信息返回示例
$ curl http://10.20.17.211:8008/v1/device/99999 \
-X PATCH \
-H 'Accept-Language: en-us' \
-d '{"name":"My-new-name"}'
响应内容
404 Not Found
Content-Type: application/json
Content-Language:en-us
{
"code": "20104",
"message": "Target device does not exist"
}
以下将对在此版本我们可能暂时无法实现(这是基于我们的开发进度和复杂度的考虑,这不代表这些特征是无关紧要的。如果你觉得应该在此版本中提供,可以把你的想法通过邮件告诉我们),但在未来可能实现的接口特征作一些说明。
有时候 API 使用者不需要返回结果的所有字段,而是部分字段。在进行横向限制的时候(例如只返回API结果的前十条记录)还应该可以进行纵向限制。这个功能能有效减少网络带宽的压力和提高传输速度。实现该功能可以使用 fields
参数来筛选返回的字段。
GET /inn/100/devices?fields=device_id,name
响应内容
{
"total_count": "2",
"items": [
{
"device_id": "10056",
"name": "黄河会议室"
},
{
"device_id": "10057",
"name:": "长江会议室"
}
]
}
如果你的 HTTP客户端获取状态码或头信息比较困难,或者你希望使用 JSONP 进行跨域请求时,我们可以把响应的所有内容(包括响应头)全部组装好放在响应内容里。只需要加上 envelope=true 请求参数,而此时接口只会返回 200 状态码。而真正的状态码、头信息以及响应内容都会在组装好的响应内容里(包装在信封里)。
GET /inn/100/devices/does-not-exist?envelope=true
响应内容
200 OK
Content-Type: application/json
Content-Language:zh-cn
{
"status": 404,
"headers": {
"Content-Type": "application/json",
"Content-Language": "zh-cn"
},
"response": {
"code": "20104",
"message": "你所请求的设备不存在"
}
}
新版设备管理系统API 即第二版API 将发生以下变化:
all_pages
Accept-Language
423 Business Error
错误,所有的验证错误都是 422 Unprocesable entity
Content-Type: application/json
为了更好的接口体验,我们错误代码的设计,将参考较为完善的微博开发平台 API,点击查看微博API的错误码。
在编写此文档时,我觉得直接使用英文更能直接说明我们的目的,所以这里的标题大多直接使用了英文,这对了解REST的开发者也是友好的。
新版本的接口,我们将准备按照本文档进行重新开发。由于改动较大,我们准备将其直接升级到第二版。文档初稿中会有不完善的地方,如果您有任何更好的建议或者一些疑问,希望您能联系我们,谢谢。
您可以把您的想法发送到以下邮箱: 1079087531@qq.com
如果您愿意,您也可以选择 QQ 联系我们:点击弹出qq聊天窗口。