REST API: 该使用部分更新还是全部更新?
2016-11-22 00:30
204 查看
关于Rest API更新资源的讨论:
当更新一个对象的时候,是否要将完整object全部信息重新提交到服务器?还是只提交部分内容?
一种是完整提交的方案
认为在前端需要保存完整的object数据,在前端由用户做更改,
之后将完整的object重新使用PUT方法传回服务器。
这种方法的弊端在于
传送数据量过大
好处是
API幂等
后端设计简单
一种是部分提交的方案
认为每次在前端更改内容的时候,只将更新的内容提交到服务器即可
好处
交互流量少
弊端
当该模型某些字段可为null时,如何知道没有指定的字段,是要求置为Null还是保持原样?
事实上查阅资料后,发现这是一个架构设计的问题。
一切开端于REST API的设计原则。
根据REST API的设计哲学,每个API需要有以下几个性质:
1. 服务器-客户端原则
- 在整个应用中,需要将客户端与服务器分开,两者之间尽量解耦合,都可以分开演进
2. 无状态
- 客户端的状态不会在服务端存储。每个session的信息只在客户端存储。
3. 可缓存
- 同样的请求应该有同样的返回,使得请求可缓存。
4. 分层
- 客户端无法分辨自己是否直接连接到服务器或者是中间层。这个性质可以进一步增强可扩展性。
5. 统一的接口设计
- 这个是REST接口设计的核心。分为以下几个小原则
1. 识别资源
- 资源通过请求进行识别。识别后的资源会在服务端进行转换格式,返回到客户端。返回的格式与数据本身无关。
2. 通过资源的表达来操作资源
- 客户端需要保存完整的资源,以及必要的元信息(MetaData),使得这些信息足够对资源进行修改或删除。
3. 自解释的消息
- 每个消息需要包含足够的信息来决定如何处理这个消息。例如在指定parser的时候需要使用Internet media type来指定。
4. HATEOAS
- 字面意思是,超媒体作为应用状态转移的引擎
- 从最开始的一共请求开始,每次返回的请求能够告诉客户端,服务端还有哪些资源提供。有时可以返回带有超链接的文字。
- 客户端不需要根据服务端的数据结构进行任何定制
这些原则很多是过于严苛的。在实际操作中如果严格遵循,会给架构设计带来很大的约束。
这里我们只讨论一个细节,就是前端在修改内容的时候,是否需要上传完整的数据?
原始的REST API中,只提供Get,Put,Post,Delete四种操作。
GET:获取资源列表或单个资源。这是一种nullipotent的操作,即,操作进行多次之后,等于没有进行。对于任何正整数n,x^n = 1.
PUT: 将指定的资源进行替换。如果作用在collection上,则替换整个collection。这是一个幂等操作,即操作多次之后,等于操作一次,而且每次操作的结果是相同的。对于任何正整数n,x^n = x.
POST:一般只作用于collection上。在这个collection中新建一条记录。
DELETE:删除对应记录或collection。
这四种操作,除了POST,都有很好的性质。但针对如何对一个对象的部分字段进行更新,则一直有各种争论。
后来在2010年的时候,HTTP协议中增加了一个操作:Patch,
此时REST API也使用这个新的操作来进行资源的部分更新。
但是,这个Patch操作有许多值得注意的地方,一个是,这个操作不幂等,一个是,在进行patch操作的时候,
需要以原子操作的形式来进行,而不能同时指定多个更新字段。
例如,在更新资源时,需要指定是增加,还是更新某个字段。
以及
注意这里的op字段指定了服务器该如何操作传送过来的字段。
Patch 为何不幂等呢?
有两个解释,一个是,在两次patch请求之间,如果对应资源有改变,那么两次patch请求造成的结果不同,
返回的object也不同。
另一个解释是,当资源模型中有一个列表时,如果多次执行 add 操作,那么这个列表几次操作后得到的结果也不同。
所以,我的看法是,在尽量多的地方使用PUT,对完整资源进行更新,在必要时使用Patch,指定原子级别操作来进行部分更新。
当更新一个对象的时候,是否要将完整object全部信息重新提交到服务器?还是只提交部分内容?
一种是完整提交的方案
认为在前端需要保存完整的object数据,在前端由用户做更改,
之后将完整的object重新使用PUT方法传回服务器。
这种方法的弊端在于
传送数据量过大
好处是
API幂等
后端设计简单
一种是部分提交的方案
认为每次在前端更改内容的时候,只将更新的内容提交到服务器即可
好处
交互流量少
弊端
当该模型某些字段可为null时,如何知道没有指定的字段,是要求置为Null还是保持原样?
事实上查阅资料后,发现这是一个架构设计的问题。
一切开端于REST API的设计原则。
根据REST API的设计哲学,每个API需要有以下几个性质:
1. 服务器-客户端原则
- 在整个应用中,需要将客户端与服务器分开,两者之间尽量解耦合,都可以分开演进
2. 无状态
- 客户端的状态不会在服务端存储。每个session的信息只在客户端存储。
3. 可缓存
- 同样的请求应该有同样的返回,使得请求可缓存。
4. 分层
- 客户端无法分辨自己是否直接连接到服务器或者是中间层。这个性质可以进一步增强可扩展性。
5. 统一的接口设计
- 这个是REST接口设计的核心。分为以下几个小原则
1. 识别资源
- 资源通过请求进行识别。识别后的资源会在服务端进行转换格式,返回到客户端。返回的格式与数据本身无关。
2. 通过资源的表达来操作资源
- 客户端需要保存完整的资源,以及必要的元信息(MetaData),使得这些信息足够对资源进行修改或删除。
3. 自解释的消息
- 每个消息需要包含足够的信息来决定如何处理这个消息。例如在指定parser的时候需要使用Internet media type来指定。
4. HATEOAS
- 字面意思是,超媒体作为应用状态转移的引擎
- 从最开始的一共请求开始,每次返回的请求能够告诉客户端,服务端还有哪些资源提供。有时可以返回带有超链接的文字。
- 客户端不需要根据服务端的数据结构进行任何定制
这些原则很多是过于严苛的。在实际操作中如果严格遵循,会给架构设计带来很大的约束。
这里我们只讨论一个细节,就是前端在修改内容的时候,是否需要上传完整的数据?
原始的REST API中,只提供Get,Put,Post,Delete四种操作。
GET:获取资源列表或单个资源。这是一种nullipotent的操作,即,操作进行多次之后,等于没有进行。对于任何正整数n,x^n = 1.
PUT: 将指定的资源进行替换。如果作用在collection上,则替换整个collection。这是一个幂等操作,即操作多次之后,等于操作一次,而且每次操作的结果是相同的。对于任何正整数n,x^n = x.
POST:一般只作用于collection上。在这个collection中新建一条记录。
DELETE:删除对应记录或collection。
这四种操作,除了POST,都有很好的性质。但针对如何对一个对象的部分字段进行更新,则一直有各种争论。
后来在2010年的时候,HTTP协议中增加了一个操作:Patch,
此时REST API也使用这个新的操作来进行资源的部分更新。
但是,这个Patch操作有许多值得注意的地方,一个是,这个操作不幂等,一个是,在进行patch操作的时候,
需要以原子操作的形式来进行,而不能同时指定多个更新字段。
例如,在更新资源时,需要指定是增加,还是更新某个字段。
PATCH /users [ { "op": "add", "username": "newuser", "email": "newuser@example.org" } ]
以及
PATCH /users/123 [ { "op": "replace", "path": "/email", "value": "new.email@example.org" } ]
注意这里的op字段指定了服务器该如何操作传送过来的字段。
Patch 为何不幂等呢?
有两个解释,一个是,在两次patch请求之间,如果对应资源有改变,那么两次patch请求造成的结果不同,
返回的object也不同。
另一个解释是,当资源模型中有一个列表时,如果多次执行 add 操作,那么这个列表几次操作后得到的结果也不同。
所以,我的看法是,在尽量多的地方使用PUT,对完整资源进行更新,在必要时使用Patch,指定原子级别操作来进行部分更新。
相关文章推荐
- 使用PB调用API自动更新(非FTP模式)(二、API说明及定义(2))
- 使用PB调用API自动更新(非FTP模式)(四、统计复制文件数量函数F_CONNECT_COPYCOUNT)
- 掌握 Ajax,第 9 部分: 使用 Google Ajax Search API
- 掌握 Ajax,第 5 部分: 操纵 DOM 使用 JavaScript 即时更新 Web 页面
- [笔记]使用 .NET 和后台智能传输服务 API 来编写自动更新应用程序
- 使用PB调用API自动更新(非FTP模式)(一、STRUCTURE定义)
- 使用 .NET 和后台智能传输服务 API 来编写自动更新应用程序
- 使用 .NET 和后台智能传输服务 API 来编写自动更新应用程序
- 使用 IBM OmniFind Yahoo! Edition REST API
- 使用 .NET 和后台智能传输服务 API 来编写自动更新应用程序
- 使用PB调用API自动更新(非FTP模式)(五、复制函数F_CONNECT_COPYFILE)
- 使用 .NET 和后台智能传输服务 API 来编写自动更新应用程序
- 使用 .NET 和后台智能传输服务 API 来编写自动更新应用程序
- 使用 OpenSSL API 进行安全编程,第 2 部分: 安全握手(二)
- 使用 .NET 和后台智能传输服务 API 来编写自动更新应用程序。
- 使用PB调用API自动更新(非FTP模式)(三、连接函数F_CONNECT_COPYSERVER)
- PB使用WININET的FTP方式自动更新(一、API和全局变量)
- 使用 .NET 和后台智能传输服务 API 来编写自动更新应用程序
- 掌握 Ajax,第 9 部分: 使用 Google Ajax Search API
- 功能强大的打包工具 NSIS,全部用脚本搞定 使用经验总结帖(持续更新中。。。)