我试图在REST和JSON-RPC之间做出选择,为web应用程序开发API。它们是如何比较的?
更新2015:我发现REST在Web/HTTP上的API上更容易开发和使用,因为API可以利用客户端和服务器都理解的现有和成熟的HTTP协议。例如,API不需要任何额外的工作或设置就可以使用响应代码、报头、查询、帖子正文、缓存和许多其他特性。
RPC的基本问题是耦合。RPC客户端以多种方式与服务实现紧密耦合,在不破坏客户端的情况下更改服务实现变得非常困难:
另一方面,在REST风格中,通过在表示(HTTP报头+表示)中包含控制信息来引导客户端是非常容易的。例如:
在REST方面还有更多的区别和优势。
首先,HTTP-REST是一种“具象状态传输”体系结构。这意味着很多有趣的事情:
其次,HTTP- rest完全兼容HTTP(请参阅前一部分中的“安全”和“幂等”),因此您将能够重用HTTP库(适用于所有现有语言)和HTTP反向代理,这将使您能够实现高级功能(缓存、身份验证、压缩、重定向、重写、日志记录等),而无需代码行。
最后但并非最不重要的是,根据HTTP 1.1的设计者(以及REST的发明者):http://www.ics.uci.edu/~fielding/pubs/dissertation/evaluation.htm#sec_6_5_2的说法,使用HTTP作为RPC协议是一个巨大的错误
我已经对这个问题进行了一些详细的研究,并认为纯REST的局限性太大,RPC是最好的,尽管我的大多数应用程序都是CRUD应用程序。如果您坚持使用REST,那么您最终将会挠头思考如何轻松地将另一个所需的方法添加到API中以实现某些特殊目的。在许多情况下,使用REST实现这一点的唯一方法是为它创建另一个控制器,这可能会使程序过于复杂。
如果您决定使用RPC,唯一的区别是您显式地将动词指定为URI的一部分,这是清晰的、一致的、bug较少的,而且确实没有麻烦。特别是如果你要创建一个超越简单CRUD的应用程序,RPC是唯一的选择。我对REST的纯粹主义者还有另一个问题:HTTP POST, GET, PUT, DELETE在HTTP中有明确的含义,这些含义被REST颠覆为其他含义,仅仅是因为它们在大多数时间都适用——但不是所有时间都适用。
在编程中,我很久以前就发现,试图用一件事来表示两件事,有时会让你吃不厌。我喜欢能够对几乎每个操作都使用POST,因为它提供了按方法需要发送和接收数据的自由。你不能把整个世界都放进CRUD里。
如果您的服务只使用模型和GET/POST/PUT/DELETE模式就能正常工作,那么请使用纯REST。
我同意HTTP最初是为无状态应用程序设计的。
但是对于现代的、更复杂的(!)实时(web)应用程序,你想要使用Websockets(这通常意味着有状态性),为什么不同时使用呢?基于Websockets的JSON-RPC非常简单,所以你有以下好处:
由于您只是在设计服务器端API,所以从定义REST模型开始,然后根据需要添加JSON-RPC支持,将RPC调用的数量保持在最低限度。
(很抱歉括号用多了)
很好的回答-只是想澄清一些评论。JSON-RPC快速且易于使用,但正如前面提到的资源和参数是紧密耦合的,它倾向于依赖于使用GET/ POST的动词(api/deleteUser, api/addUser),而REST提供松散耦合的资源(api/users),在HTTP REST api中依赖于几个HTTP方法(GET, POST, PUT, PATCH, DELETE)。REST对于没有经验的开发人员来说稍微有点难实现,但是这种风格现在已经相当普遍了,而且从长远来看,它提供了更大的灵活性(使API的寿命更长)。
除了没有紧密耦合的资源外,REST还允许您避免提交到单一的内容类型中——这意味着如果您的客户端需要接收XML、JSON甚至YAML格式的数据——如果在您的系统中,您可以使用内容类型/接受标头返回其中任何一种。
这让你的API足够灵活,以支持新的内容类型或客户端需求。
但是真正将REST与JSON-RPC区别开来的是它遵循一系列经过仔细考虑的约束——确保架构的灵活性。这些约束包括确保客户端和服务器能够彼此独立地发展(您可以在不破坏客户端应用程序的情况下进行更改),调用是无状态的(状态通过超媒体表示),为交互提供统一的接口,API是在分层系统上开发的,响应是可由客户端缓存的。在按需提供代码方面还有一个可选的约束。
然而,尽管如此,大多数API都不是RESTful的(根据Fielding的说法),因为它们不包含超媒体(在响应中嵌入超文本链接,帮助导航API)。大多数api都是类似REST的,因为它们遵循大多数REST的概念,但忽略了这个约束。然而,越来越多的api正在实现这一点,它正在成为一种主流实践。
这也为你提供了一些灵活性,因为超媒体驱动的api(如Stormpath)将客户端引导到URI(这意味着如果有什么变化,在某些情况下,你可以修改URI而不产生负面影响),而与RPC一样,URI需要是静态的。使用RPC,您还需要广泛地记录这些不同的uri,并解释它们如何相互关联地工作。
一般来说,如果您想要构建一个可扩展的、灵活的、长期存在的API,我认为REST是最佳选择。基于这个原因,我认为这是99%的情况下应该走的路线。
在我看来,关键在于行动vs资源导向。REST是面向资源的,非常适合CRUD操作,并且由于其已知的语义为第一个用户提供了一些可预测性,但是当从方法或过程实现时,将迫使您提供对以资源为中心的世界的人工转换。另一方面,RPC非常适合面向操作的api,在这种api中,您公开的是服务,而不是可用于RPC的资源集。
毫无疑问REST更受欢迎,如果你想将API公开给第三方,这无疑会增加一些好处。
如果不是(例如在SPA中创建AJAX前端),我的选择是RPC。特别是JSON- rpc,结合JSON Schema作为描述语言,并根据用例通过HTTP或Websockets传输。
json - rpc是一个简单而优雅的规范,它定义了用于同步或异步RPC的请求和响应JSON有效负载。
JSON模式是一个规范草案,定义了一个基于JSON的格式,旨在描述JSON数据。通过使用JSON Schema描述您的服务输入和输出消息,您可以在消息结构中拥有任意的复杂性,而不会影响可用性,并且可以自动化服务集成。
传输协议(HTTP vs websockets)的选择取决于不同的因素,最重要的是你是否需要HTTP特性(缓存、重新验证、安全性、幂等性、内容类型、多部分等等),或者你的应用程序是否需要在高频率下交换消息。
到目前为止,这主要是我个人对这个问题的看法,但是现在有一些东西可以真正帮助那些阅读这些行的Java开发人员,我在过去的一年里一直在工作的框架,诞生于你现在想知道的同一个问题:
http://rpc.brutusin.org
你可以在这里看到一个现场演示,展示了用于功能测试的内置存储库浏览器(感谢JSON Schema)和一系列示例服务:
http://demo.rpc.brutusin.org
希望对伴侣有帮助!
玉米片
REST与HTTP紧密耦合,因此如果您只通过HTTP公开API,那么REST更适合于大多数(但不是所有)情况。然而,如果你需要通过其他传输方式(如消息传递或web套接字)公开你的API,那么REST就不适用了。
我过去一直是REST的忠实粉丝,它在纸上比RPC有很多优势。你可以给客户端提供不同的内容类型、缓存、HTTP状态代码的重用,你可以通过API引导客户端,如果API不是大部分都是自解释的,你可以在API中嵌入文档。
但我的经验是,在实践中,这是站不住脚的,相反,你做了很多不必要的工作,以使一切正确。此外,HTTP状态代码通常不能精确地映射到您的域逻辑,在您的上下文中使用它们通常感觉有点勉强。但在我看来,REST最糟糕的地方在于,您花费了大量时间来设计资源及其允许的交互。无论何时,当你对API进行一些重要的添加时,你都希望找到一个好的解决方案来添加新功能,而不是把自己设计到一个角落里。
对我来说,这通常感觉是浪费时间,因为大多数时候,我已经对如何将API建模为一组远程过程调用有了非常好的和明显的想法。如果我已经在REST的约束下对我的问题进行了建模,那么下一个问题是如何从客户端调用它?我们的程序基于调用过程,因此构建一个好的RPC客户端库很容易,构建一个好的REST客户端库就不那么容易了,在大多数情况下,你只需要从服务器上的REST API映射回客户端库中的一组过程。
正因为如此,今天对我来说,RPC感觉更简单、更自然。不过,我真正怀念的是一个一致的框架,它可以很容易地编写自描述和可互操作的RPC服务。因此,我创建了自己的项目来试验新的方法,使RPC对我自己更容易,也许其他人也会发现它有用:https://github.com/aheck/reflectrpc
最好在REST和JSON-RPC之间选择JSON-RPC,为web应用程序开发一个更容易理解的API。JSON-RPC是首选,因为它对方法调用和通信的映射很容易理解。
选择最合适的方法取决于约束条件或主要目标。例如,只要性能是一个主要特征,就建议使用JSON-RPC(例如,高性能计算)。但是,如果主要目标是不可知,以便提供一个通用的接口供其他人推断,则建议使用REST。如果两个目标都需要实现,建议同时包含两个协议。
将REST从JSON-RPC中分离出来的事实是,它遵循了一系列经过仔细考虑的约束——确认了架构的灵活性。这些约束包括确保客户端和服务器能够彼此独立地增长(可以在不破坏客户端应用程序的情况下进行更改),调用是无状态的(状态被视为超媒体),为交互提供统一的接口,API是在分层系统上的高级API (Hall, 2010)。JSON-RPC是快速且易于使用的,但是正如前面提到的资源和参数是紧密耦合的,它可能依赖于使用GET/ POST的动词(api/addUser, api/deleteUser),而REST在HTTP中提供松散耦合的资源(api/users)。REST API依赖于一些HTTP方法,如GET、PUT、POST、DELETE、PATCH。对于没有经验的开发人员来说,实现REST稍微有点困难。
JSON(表示为JavaScript对象符号)是一种轻量级的数据交换格式,易于人类阅读和编写。机器解析和生成是没有麻烦的。JSON是一种完全独立于语言的文本格式,但实践了由c#、C、c++、Java、Perl、JavaScript、Python和许多其他语言组成的语言家族的程序员所熟悉的约定。这些属性使JSON成为一种完美的数据交换语言和更好的选择。
如果您请求资源,那么RESTful API在设计上更好。如果您请求一些具有大量参数和复杂方法的复杂数据,而不是简单的CRUD,那么RPC是正确的方法。
您可以使用JSON-RPC与“较少的字句”;(没有方法),并保留sendo id、参数、错误代码和警告消息所需的最小标准化。JSON-RPC标准没有说“你不能rest”,只是说如何打包基本信息。
“其他JSON-RPC"存在 !是REST与“最佳实践”,为最少的信息包装,与简单和可靠的合同。
(来自这个答案和didactic context)
在处理REST时,从资源的角度考虑通常会有所帮助。在这种情况下,资源不仅仅是“银行账户”;但这是一个银行账户的交易…但是JSON-RPC并没有强制要求“方法”;参数,所有都是由"path"端点的。
REST 存款 with POST /Bank/Account/John/Transaction with JSON request {"jsonrpc": "2.0", "id": 12, "params": {"currency":"USD","amount":10}}. >JSON响应可以是{"jsonrpc": "2.0", "result": "sucess", "id": 12}
POST /Bank/Account/John/Transaction
{"jsonrpc": "2.0", "id": 12, "params": {"currency":"USD","amount":10}}
{"jsonrpc": "2.0", "result": "sucess", "id": 12}
REST 撤回 with POST /Bank/Account/John/Transaction…相似的。
GET /Bank/Account/John/Transaction/12345@13
{"jsonrpc": "2.0", "result": {"debits":[...],"credits":[...]}, "id": 13}
为什么JSON RPC:
对于REST api,我们必须为可能需要的每个功能/方法定义一个控制器。因此,如果我们想让客户端访问10个方法,我们就必须编写10个控制器来将客户端请求连接到特定的方法。
另一个因素是,即使我们为每个方法/功能使用不同的控制器,客户端也必须记住是使用POST还是GET。这使事情更加复杂。为了发送数据,如果使用POST,则必须设置请求的内容类型。
对于JSONRPC,事情大大简化了,因为大多数JSONRPC服务器操作POST HTTP方法,内容类型始终是application/ JSON。这减轻了在客户端使用正确的HTTP方法和内容设置的负担。
不必为服务器想要向客户端公开的不同方法/功能创建单独的控制器。
为什么休息:
对于服务器希望向客户端公开的不同功能,有不同的url。因此,您可以嵌入这些url。
这些观点大多是有争议的,完全取决于一个人的需要。
我认为,一如既往,这取决于……
REST具有广泛的公众支持的巨大优势,这意味着有大量的工具和书籍。如果你需要制作一个API,让来自不同组织的大量消费者使用,那么只有一个原因:它是受欢迎的。作为一种协议,它当然是完全失败的,因为有太多完全不同的方法来将命令映射到URL/动词/响应。
因此,当你编写一个需要与后端对话的单页web应用程序时,我认为REST太复杂了。在这种情况下,你不必担心长期的兼容性,因为应用程序和API可以一起发展。
我曾经为一个单页web应用程序开始使用REST,但是web应用程序和服务器之间的细粒度命令很快就把我逼疯了。我应该把它编码为路径参数吗?在身体里?查询参数?一个头?在完成URL/Verb/Response设计后,我必须用Javascript编写这些代码,用Java编写解码器,然后调用实际的方法。尽管有很多工具,但在域代码中不使用任何HTTP语义是非常棘手的,这是非常糟糕的实践。(衔接)
尝试为中等复杂的站点制作一个Swagger/OpenAPI文件,并将其与该文件中描述远程过程的单个Java接口进行比较。复杂性的增长是惊人的。
因此,对于单页web应用程序,我从REST切换到JSON-RPC。aI开发了一个小型库,在服务器上编码Java接口,并将其传送到浏览器。在浏览器中,这为为每个函数返回承诺的应用程序代码创建了一个代理。
同样,REST也有它的地位,因为它很有名,因此得到了很好的支持。认识到底层的无状态资源哲学和层次模型也很重要。然而,这些原则同样可以在RPC模型中使用。JSON RPC工作于HTTP之上,因此它在这方面具有与REST相同的优势。不同之处在于,当您不可避免地遇到这些不能很好地映射到这些原则的函数时,您不必被迫做大量不必要的工作。
根据理查德森成熟度模型,问题不是REST与RPC,而是休息多少?
从这个角度来看,REST标准的遵从性可以分为4个级别。
根据REST标准的创建者,只有第3级服务可以被称为RESTful服务。然而,这是一个度量合规,而不是质量。如果您只想调用一个执行计算的远程函数,那么在响应中包含相关的超媒体链接可能没有意义,也没有根据所使用的HTTP谓词区分行为的意义。因此,这样的调用本质上更倾向于rpc。然而,较低的遵从性级别并不一定意味着有状态性或更高的耦合。也许,你应该尽可能多地使用REST,而不是思考REST与RPC。不要为了符合RESTful遵从性标准而扭曲应用程序。