存储 REST API
REST API 可以让你用任何支持发送 HTTP 请求的设备来与云服务进行交互,你可以使用 REST API 做很多事情,比如:
- 使用任何编程语言操作云端数据。
- 如果你不再需要使用云服务,你可以导出你所有的数据。
- 一个追求最少化依赖库的应用可以不引入 SDK,直接访问 REST API 获取云服务上的数据。
- 你可以批量新增大量数据,供应用之后读取。
- 你可以下载最近的数据用于离线分析和归档备份。
API 版本
当前的 API 版本是 1.1
。
在线测试
为了方便测试 REST API,文档给出了 curl 命令示例,示例针对类 unix 平台(macOS、Linux 等)编写,直接粘贴至 Windows 平台 cmd.exe 很可能无法工作。
例如,curl 命令示例中的 shell 换行符(\
)在 cmd.exe 中是目录分隔符。
Windows 平台建议使用 Postman 等客户端测试。
点击展开 Postman 示例
Postman 可直接导入 curl 命令。
Postman 还支持自动生成多种语言(库)调用 REST API 的代码。
Base URL
REST API 请求的 Base URL(下文 curl 示例中用 {{host}}
表示)即应用绑定的 API 自定义域名,可以在 开发者中心 > 你的游戏 > 游戏服务 > 应用配置 > 域名配置 绑定、查看。
详见文档关于域名的说明。
对象
URL | HTTP | 功能 |
---|---|---|
/1.1/classes/<className> | POST | 创建对象 |
/1.1/classes/<className>/<objectId> | GET | 获取对象 |
/1.1/classes/<className>/<objectId> | PUT | 更新对象 |
/1.1/classes/<className> | GET | 查询对象 |
/1.1/classes/<className>/<objectId> | DELETE | 删除对象 |
/1.1/scan/classes/<className> | GET | 按照特定顺序遍历 Class |
角色
URL | HTTP | 功能 |
---|---|---|
/1.1/roles | POST | 创建角色 |
/1.1/roles/<objectId> | GET | 获取角色 |
/1.1/roles/<objectId> | PUT | 更新角色 |
/1.1/roles | GET | 查询角色 |
/1.1/roles/<objectId> | DELETE | 删除角色 |
数据 Schema
URL | HTTP | 功能 |
---|---|---|
/1.1/schemas | GET | 获取应用所有 Class 的 Schema |
/1.1/schemas/<className> | GET | 获取应用指定 Class 的 Schema |
其他 API
URL | HTTP | 功能 |
---|---|---|
/1.1/date | GET | 获得服务端当前时间 |
/1.1/exportData | POST | 请求导出应用数据 |
/1.1/exportData/<id> | GET | 获取导出数据任务状态和结果 |
应用凭证
在 开发者中心 > 你的游戏 > 游戏服务 > 应用配置 可以查看应用的基本信息:
- Client ID:又称
App ID
,在 SDK 初始化时用到。 - Client Token:又称
App Key
,客户端对服务端的调用凭证,在 SDK 初始化时用到。 - 域名配置 > 云服务 API:又称 API 域名或 Server URL,在客户端 SDK 初始化时用到。域名配置 参考下一节域名。
- Server Secret:又称
Master Key
,用于在自有服务器、云引擎等受信任环境调用管理接口,具备跳过一切权限验证的超级权限。所以一定注意保密,千万不要在客户端代码中使用该凭证。
请求格式
对于 POST 和 PUT 请求,请求的主体必须是 JSON 格式,而且 HTTP header 的 Content-Type
需要设置为 application/json
。
用户验证通过 HTTP header 来进行,X-LC-Id
标明正在运行的是哪个应用(应用的 App ID
,对应到开发者中心游戏的 Client ID
),X-LC-Key
用来授权鉴定 endpoint:
curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"content": "更新一篇博客的内容"}' \
https://{{host}}/1.1/classes/Post/<objectId>
X-LC-Key
通常情况下是应用的 App Key
(对应到开发者中心游戏的 Client Token
),有些情况(需要超级权限的操作)下是应用的 Master Key
(对应到开发者中心游戏的 Server Secret
)。
当 X-LC-Key
值为 Master Key
时,需要在其后添加 ,master
后缀以示区分,例如:
X-LC-Key: {{masterkey}},master
对于 JavaScript 使用,云服务支持跨域资源共享,所以你可以将这些 header 同 XMLHttpRequest
一同使用。
REST API 通讯支持 gzip
和 brotli
压缩,客户端可以通过指定相应的 Accept-Encoding
HTTP 头开启压缩。
更安全的鉴权方式
我们还支持一种新的 API 鉴权方式,即在 HTTP header 中使用 X-LC-Sign
来代替 X-LC-Key
,以降低 App Key
的泄露风险。例如:
curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Sign: d5bcbb897e19b2f6633c716dfdfaf9be,1453014943466" \
-H "Content-Type: application/json" \
-d '{"content": "在 HTTP header 中使用 X-LC-Sign 来更新一篇博客的内容"}' \
https://{{host}}/1.1/classes/Post/<objectId>
X-LC-Sign
的值是由 sign,timestamp[,master]
组成的字符串:
取值 | 约束 | 描述 |
---|---|---|
sign | 必须 | 将 timestamp 加上 App Key 或 Master Key 组成的字符串,再对它做 MD5 签名后的结果。 |
timestamp | 必须 | 客户端产生本次请求的 unix 时间戳(UTC),精确到毫秒。 |
master | 可选 | 字符串 "master" ,当使用 master key 签名请求的时候,必须加上这个后缀明确说明是使用 master key。 |
注意,sign
中的 MD5 签名的 hex 值中的字母请使用小写。如果使用大写字母,会导致签名校验失败。
举例来说,假设应用的信息如下:
App Id | FFnN2hso42Wego3pWq4X5qlu |
App Key | UtOCzqb67d3sN12Kts4URwy8 |
Master Key | DyJegPlemooo4X1tg94gQkw1 |
请求时间 | 2016-01-17 15:15:43.466 GMT+08:00 |
timestamp | 1453014943466 |
使用 App Key
来计算 sign:
md5( timestamp + App Key )
= md5(1453014943466UtOCzqb67d3sN12Kts4URwy8)
= d5bcbb897e19b2f6633c716dfdfaf9be
-H "X-LC-Sign: d5bcbb897e19b2f6633c716dfdfaf9be,1453014943466" \
使用 Master Key
来计算 sign:
md5( timestamp + Master Key )
= md5(1453014943466DyJegPlemooo4X1tg94gQkw1)
= e074720658078c898aa0d4b1b82bdf4b
-H "X-LC-Sign: e074720658078c898aa0d4b1b82bdf4b,1453014943466,master" \
(最后加上 ,master
来告诉服务器这个签名是使用 master key 生成的。)
使用 master key 将绕过所有权限校验,应该确保只在可控环境中使用,比如自行开发的管理平台,并且要完全避免泄露。 以上两种计算 sign 的方法可以根据实际情况来选择一种使用。
指定 hook 函数调用环境
请求可能触发云引擎的 hook 函数,可以通过设置 HTTP 头 X-LC-Prod
来区分调用的环境。
X-LC-Prod: 0
表示调用预备环境X-LC-Prod: 1
表示调用生产环境
默认(未指定 X-LC-Prod
头)调用生产环境的 hook 函数。
响应格式
对于所有的请求, 响应格式都是一个 JSON 对象。
一个请求是否成功是由 HTTP 状态码标明的。一个 2XX 的状态码表示成功,而一个 4XX 表示请求失败。当一个请求失败时响应的主体仍然是一个 JSON 对象,但是总是会包含 code
和 error
这两个字段,你可以用它们来进行调试。举个例子,如果尝试用非法的属性名来保存一个对象会得到如下信息:
{
"code": 105,
"error": "Invalid key name. Keys are case-sensitive and 'a-zA-Z0-9_' are the only valid characters. The column is: 'invalid?'."
}
对象
对象格式
数据存储服务是建立在 LCObject(对象)基础上的,每个 LCObject 包含若干属性值对(key-value,也称「键值对」),属性的值是与 JSON 格式兼容的数据。 通过 REST API 保存对象需要将对象的数据通过 JSON 来编码。这个数据是无模式化的(schema free),这意味着你不需要提前标注每个对象上有哪些 key,你只需要随意设置键值对就可以,后端会保存它。
举个例子,假如我们要实现一个类似于微博的社交 App,主要有三类数据:账户、帖子、评论,一条微博帖子可能包含下面几个属性:
{
"content": "每个 Java 程序员必备的 8 个开发工具",
"pubUser": "官方客服",
"pubTimestamp": 1435541999
}
Key(属性名)必须是字母、数字、下划线组成的字符串,Value(属性值)可以是任何可以 JSON 编码的数据。
每个对象都有一个类名,你可以通过类名来区分不同的数据。例如,我们可以把微博的帖子对象称之为 Post。我们建议将类和属性名分别按照 NameYourClassesLikeThis
和 nameYourKeysLikeThis
这样的惯例来命名,即区分第一个字母的大小写,这样可以提高代码的可读性和可维护性。
当你从云端获取对象时,一些字段会被自动加上,如 createdAt
、updatedAt
和 objectId
。这些字段的名字是保留的,值也不允许修改。我们上面设置的对象在获取时应该是下面的样子:
{
"content": "每个 Java 程序员必备的 8 个开发工具",
"pubUser": "官方客服",
"pubTimestamp": 1435541999,
"createdAt": "2015-06-29T01:39:35.931Z",
"updatedAt": "2015-06-29T01:39:35.931Z",
"objectId": "558e20cbe4b060308e3eb36c"
}
createdAt
和 updatedAt
都是 UTC 时间戳,以 ISO 8601 标准和毫秒级精度储存:YYYY-MM-DDTHH:MM:SS.MMMZ
。objectId
是一个字符串,在类中可以唯一标识一个实例。
在 REST API 中,class 级的操作都是通过一个带类名的资源路径(URL)来标识的。例如,如果类名是 Post
,那么 class 的 URL 就是:
https://{{host}}/1.1/classes/Post
对于用户账户这种对象,有一个特殊的 URL:
https://{{host}}/1.1/users
针对于一个特定的对象的操作可以通过组织一个 URL 来做。例如,对 Post
中的一个 objectId
为 558e20cbe4b060308e3eb36c
的对象的操作应使用如下 URL:
https://{{host}}/1.1/classes/Post/558e20cbe4b060308e3eb36c
创建对象
创建一个新的对象,应该向 class 的 URL 发送一个 POST 请求,其中应该包含对象本身。 例如,要创建如上所说的对象:
curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"content": "每个 Java 程序员必备的 8 个开发工具","pubUser": "官方客服","pubTimestamp": 1435541999}' \
https://{{host}}/1.1/classes/Post
当创建成功时,HTTP 的返回是 201 Created,而 header 中的 Location 表示新的 object 的 URL:
Status: 201 Created
Location: https://{{host}}/1.1/classes/Post/558e20cbe4b060308e3eb36c
响应的主体是一个 JSON 对象,包含新的对象的 objectId 和 createdAt 时间戳。
{
"createdAt": "2015-06-29T01:39:35.931Z",
"objectId": "558e20cbe4b060308e3eb36c"
}
如果希望返回新创建的对象的完整信息,可以在 URL 里加上 fetchWhenSave
选项,并且设置为 true:
curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"content": "每个 Java 程序员必备的 8 个开发工具","pubUser": "官方客服","pubTimestamp": 1435541999}' \
https://{{host}}/1.1/classes/Post?fetchWhenSave=true
Class 名称只能包含字母、数字、下划线。 **每个应用最多可以创建 500 个 class,每个 class 最多包含 300 个字段,**但每个 class 中的记录数量没有限制。
获取对象
当你创建了一个对象时,你可以通过发送一个 GET 请求到返回的 header 的 Location 以获取它的内容。例如,为了得到我们上面创建的对象:
curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
https://{{host}}/1.1/classes/Post/558e20cbe4b060308e3eb36c
返回的主体是一个 JSON 对象包含所有用户提供的 field 加上 createdAt、updatedAt 和 objectId 字段:
{
"content": "每个 Java 程序员必备的 8 个开发工具",
"pubUser": "官方客服",
"pubTimestamp": 1435541999,
"createdAt": "2015-06-29T01:39:35.931Z",
"updatedAt": "2015-06-29T01:39:35.931Z",
"objectId": "558e20cbe4b060308e3eb36c"
}
当获取的对象有指向其子对象的指针时,你可以加入 include
选项来获取这些子对象。假设微博记录中有一个字段 author
来指向发布者的账户信息,按上面的例子,可以这样来连带获取发布者完整信息:
curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'include=author' \
https://{{host}}/1.1/classes/Post/<objectId>
include
支持点号,例如,假定发布者有一个字段 department
指向发布者所属的部门,那么可以使用 include=author.department
一并获取部门信息。
类不存在时,返回 404 Not Found 错误:
{
"code": 101,
"error": "Class or object doesn't exists."
}
objectId 不存在时,返回一个空对象(HTTP 状态码为 200 OK):
{}
某些特殊的系统内置类(类名以下划线开头),objectId 不存在时不一定返回空对象。
例如,查询 _User
时,objectId 不存在会返回 400 Bad Request 错误:
curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
https://{{host}}/1.1/classes/_User/<NonexistObjectId>
返回:
{
"code": 211,
"error": "Could not find user."
}
顺带提一下,获取用户推荐使用 GET /users/<objectId>
,而不是直接查询 _User
类。
参见后文获取用户一节。
更新对象
为了更改一个对象已经有的数据,你可以发送一个 PUT 请求到对象相应的 URL 上,任何你未指定的 key 都不会更改,所以你可以只更新对象数据的一个子集。例如,我们来更改我 们对象的一个 content 字段:
curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"content": "每个 JavaScript 程序员必备的 8 个开发工具:http://buzzorange.com/techorange/2015/03/03/9-javascript-ide-editor/"}' \
https://{{host}}/1.1/classes/Post/<objectId>
返回的 JSON 对象只会包含一个 updatedAt 字段,表明更新发生的时间:
{
"updatedAt": "2015-06-30T18:02:52.248Z"
}
fetchWhenSave
选项对更新对象也同样有效。
但和创建对象不同,用于更新对象时仅返回更新的字段,而非全部字段。
计数器
比如一条微博,我们需要记录有多少人喜欢或者转发了它,但可能很多次喜欢都是同时发 生的,如果每个客户端都直接把读到的计数值更改之后再写回去,那么极容易引发冲突和覆盖,导致最终结果不准。 云服务提供了对数字类型字段进行原子增加或者减少的功能,稳妥地实现对计数器类型数据的更新:
curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"upvotes":{"__op":"Increment","amount":1}}' \
https://{{host}}/1.1/classes/Post/<objectId>
这样就将对象的 upvotes
属性值(被用户点赞的次数)加上 1,其中 amount
为递增的数字大小,如果为负数,则为递减。
除了 Increment,我们也提供了 Decrement 用于递减,等价于 Increment 一个负数。
注意,虽然原子增减支持浮点数,但因为底层数据库的浮点数存储格式限制,会有舍入误差。
因此,需要原子增减的字段建议使用整数以避免误差,例如 3.14
可以存储为 314
,然后在客户端进行相应的转换。
否则,以比较大小为条件查询对象的时候,需要特殊处理,
< a
需改查 < a + e
,> a
需改查 > a - e
,== a
需改查 > a - e
且 < a + e
,其中 e
为误差范围,据所需精度取值,比如 0.0001
。
位运算
如果数据表的某一列是整型,可以使用位运算操作符该列进行原子的位运算:
- BitAnd 与运算
- BitOr 或运算
- BitXor 异或运算
curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"flags":{"__op":"BitOr","value": 0x0000000000000004}}' \
https://{{host}}/1.1/classes/Post/<objectId>
数组
有 3 种原子性操作可用于存储和更改数组类型的字段:
- Add:在一个数组字段的后面添加一些指定的对象(包装在一个数组内)
- AddUnique:只会在数组内原本没有这个对 象的情形下才会添加入数组,插入的位置不定。
- Remove:从一个数组内移除所有的指定的对象
每种操作都有一个 key objects
,其值为被添加或删除的对象列表。例如为每条微博增加一个「标签」属性 tags,然后往里面加入一些值:
curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"tags":{"__op":"AddUnique","objects":["Frontend","JavaScript"]}}' \
https://{{host}}/1.1/classes/Post/<objectId>
有条件更新对象
假设从某个账户对象 Account 的余额中扣除一定金额,但是要求余额要大于等于被扣除的金额才允许操作,那么就需要通过 where
参数为更新操作加上限定条件 balance >= amount
:
curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"balance":{"__op":"Decrement","amount": 30}}' \
"https://{{host}}/1.1/classes/Account/558e20cbe4b060308e3eb36c?where=%7B%22balance%22%3A%7B%22%24gte%22%3A%2030%7D%7D"
URL 中 where 参数的值是 %7B%22balance%22%3A%7B%22%24gte%22%3A%2030%7D%7D
,其实这是 {"balance":{"$gte": 30}}
被 URL 编码后的结果。
如果条件不满足,更新将失败,同时返回错误码 305
:
{
"code": 305,
"error": "No effect on updating/deleting a document."
}
特别强调:where 一定要作为 URL 的 Query Parameters 传入。
__op 操作汇总
使用 __op("操作名称", {JSON 参数})
函数可以完成原子性操作,确保数据的一致性。
操作 | 说明 | 示例 |
---|---|---|
Delete | 删除对象的一个属性 | __op('Delete', {'delete': true}) |
Add | 在数组末尾添加对象 | __op('Add',{'objects':['Apple','Google']}) |
AddUnique | 在数组末尾添加不会重复的对象,插入位置不定 | __op('AddUnique', {'objects':['Apple','Google']}) |
Remove | 从数组中删除对象 | __op('Remove',{'objects':['Apple','Google']}) |
AddRelation | 添加一个关系 | __op('AddRelation', {'objects':[pointer('_User','558e20cbe4b060308e3eb36c')]}) |
RemoveRelation | 删除一个关系 | __op('RemoveRelation', {'objects':[pointer('_User','558e20cbe4b060308e3eb36c')]}) |
Increment | 递增 | __op('Increment', {'amount': 50}) |
Decrement | 递减 | __op('Decrement', {'amount': 50}) |
BitAnd | 与运算 | __op('BitAnd', {'value': 0x0000000000000004}) |
BitOr | 或运算 | __op('BitOr', {'value': 0x0000000000000004}) |
BitXor | 异或运算 | __op('BitXor', {'value': 0x0000000000000004}) |
删除对象
要在云端删除一个对象,可以发送一个 DELETE 请求到指定的对象的 URL,比如:
curl -X DELETE \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
https://{{host}}/1.1/classes/Post/<objectId>
还可以使用 Delete 操作删除一个对象的一个字段(注意此时 HTTP Method 是 PUT):
curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{"downvotes":{"__op":"Delete"}}' \
https://{{host}}/1.1/classes/Post/<objectId>
有条件删除对象
为请求增加 where
参数即可以按指定的条件来删除对象。例如删除点击量 clicks 为 0 的帖子:
curl -X DELETE \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
"https://{{host}}/1.1/classes/Post/<objectId>?where=%7B%22clicks%22%3A%200%7D"
URL 中 where 参数的值是 %7B%22clicks%22%3A%200%7D
,其实这是 {"clicks": 0}
被 URL 编码后的结果。
如果条件不满足,删除将失败,同时返回错误码 305
:
{
"code": 305,
"error": "No effect on updating/deleting a document."
}
特别强调:where 一定要作为 URL 的 Query Parameters 传入。
遍历 Class
因为更新和删除都是基于单个对象的,都要求提供 objectId,但是有时候用户需要高效地遍历一个 Class,做一些批量的更新或者删除的操作。
通常情况下,如果 Class 的数量规模不大,使用查询加上 skip
和 limit
分页配合排序 order
就可以遍历所有数据。
但是当 Class 数量规模比较大的时候, skip
的效率就非常低了(这跟 MySQL 等关系数据库的原因一样,深度翻页比较慢)。
为了避免性能问题,这种情况下可以通过指定 createdAt
或 updatedAt
的范围来实现翻页。
我们还额外提供了 scan
接口,可以按照特定字段排序来高效地遍历一张表,相比指定 createdAt
或 updatedAt
范围来翻页的写法也更加直截了当。
默认情况下,按 objectId
升序,同时支持设置 limit
限定每一批次的返回数量,默认 limit 为 100,最大 可设置为 1000:
curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-G \
--data-urlencode 'limit=10' \
https://{{host}}/1.1/scan/classes/Article
scan
强制要求使用 MasterKey
。
返回:
{
"results": [
{
"tags": ["clojure", "\u7b97\u6cd5"],
"createdAt": "2016-07-07T08:54:13.250Z",
"updatedAt": "2016-07-07T08:54:50.268Z",
"title": "clojure persistent vector",
"objectId": "577e18b50a2b580057469a5e"
}
//...
],
"cursor": "pQRhIrac3AEpLzCA"
}
其中 results
对应的就是返回的对象列表,而 cursor
表示本次遍历当前位置的「指针」,当 cursor
为 null 的时候,表示已经遍历完成,如果不为 null,请继续传入 cursor
到 scan
接口就可以从上次到达的位置继续往后查找:
curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-G \
--data-urlencode 'limit=10' \
--data-urlencode 'cursor=pQRhIrac3AEpLzCA' \
https://{{host}}/1.1/scan/classes/Article
每次返回的 cursor
的有效期是 10 分钟。
遍历还支持过滤条件,加入 where 参数:
curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-G \
--data-urlencode 'limit=10' \
--data-urlencode 'where={"score": 100}' \
https://{{host}}/1.1/scan/classes/Article
默认情况下系统按 objectId
升序排序,增加 scan_key
参数可以使用其他字段来排序:
curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-G \
--data-urlencode 'limit=10' \
--data-urlencode 'scan_key=score' \
https://{{host}}/1.1/scan/classes/Article
scan_key 也支持倒序,前面加个减号即可,例如 -score
。
自定义的 scan_key 需要满足严格单调递增的条件,并且 scan_key 不可作为 where 查询条件存在。
scan 不支持 include 参数,调用 scan 时传入 include 参数是未定义行为。
如果遍历 Class 时需要使用 include 参数,请使用普通的查询,并通过指定 createdAt
或 updatedAt
的范围来实现翻页。
批量操作
为了减少网络交互的次数太多带来的时间浪费,你可以在一个请求中对多个对象进行 create、update、delete 操作。
在一个批次中每一个操作都有相应的方法、路径和主体,这些参数可以代替你通常会使用的 HTTP 方法。这些操作会以发送过去的顺序来执行,比如我们要一次发布一系列的微博:
curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{
"requests": [
{
"method": "POST",
"path": "/1.1/classes/Post",
"body": {
"content": "2021 年 5 月 1 日至 2021 年 5 月 5 日放假五天,5 月 8 日调休正常上班。",
"pubUser": "官方客服"
}
},
{
"method": "POST",
"path": "/1.1/classes/Post",
"body": {
"content": "我们将于 2021 年 2 月 10 日至 2021 年 2 月 17 日放假八天,2 月 18 日恢复正常工作,放假期间,运维团队仍将在线值班,以应对可能的突发情况,保障服务稳定。",
"pubUser": "官方客服"
}
}
]
}' \
https://{{host}}/1.1/batch
我们对每一批次中所包含的操作数量(requests 数组中的元素个数)暂不设限,但考虑到云端对每次请求的 body 内容大小有 20 MB 的限制,因此建议将每一批次的操作数量控制在 100 以内。
批量操作的响应 body 会是一个列表,列表的元素数量和顺序与给定的操作请求是一致的。每一个在列表中的元素都有一个字段是 success 或者 error。
[
{
"error": {
"code": 1,
"error": "Could not find object by id '558e20cbe4b060308e3eb36c' for class 'Post'."
}
},
{
"success": {
"updatedAt": "2017-02-22T06:35:29.419Z",
"objectId": "58ad2e850ce463006b217888"
}
}
]
需要注意,即使一个 batch 请求返回的响应码为 200,这仅代表服务端已收到并处理了这个请求,但并 不说明该 batch 中的所有操作都成功完成,只有当返回 body 的列表中不存在 error 元素,开发者才可以认为所有操作都已成功完成。
在 batch 操作中 update 和 delete 同样是有效的:
curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '{
"requests": [
{
"method": "PUT",
"path": "/1.1/classes/Post/55a39634e4b0ed48f0c1845b",
"body": {
"upvotes": 2
}
},
{
"method": "DELETE",
"path": "/1.1/classes/Post/55a39634e4b0ed48f0c1845c"
}
]
}' \
https://{{host}}/1.1/batch
批量操作还有一个冷门用途,代替 URL 过长的 GET(比如使用 containedIn 等方法构造查询)和 DELETE (比如批量删除)请求,以绕过服务端和某些客户端对 URL 长度的限制。