soap rest
Written by Pascal Chambon, reviewed by Raphaël Gomès
由Pascal Chambon撰写,由RaphaëlGomès评论
Update: this article mostly deals with the RESTish ecosystem, which now constitutes a major part of webservices. For more in-depth analysis of the original REST, and of HATEOAS, see my follow-up article.
更新 :本文主要讨论RESTish生态系统,该生态系统现在已构成Web服务的主要部分。 有关原始REST和HATEOAS的更深入分析,请参阅我的后续文章 。
Some years ago, I developed a new information system in a big telecom company. We had to communicate with an increasing number of web services, exposed by older systems or by business partners.
几年前,我在一家大型电信公司开发了一个新的信息系统。 我们不得不与越来越多的Web服务进行通信,这些服务由较旧的系统或业务合作伙伴提供。
Needless to say, we had our fair share of SOAP Hell. Abstruse WSDLs, incompatible libraries, weird bugs… So whenever we could, we advocated — and used — simple Remote Procedure Call protocols: XMLRPC or JSONRPC.
不用说,我们有相当一部分SOAP Hell。 复杂的WSDL ,不兼容的库,怪异的错误……因此,我们尽可能提倡并使用简单的远程过程调用协议:XMLRPC或JSONRPC。
Our first servers and clients for these protocols were pretty basic, limited, fragile. But gradually, we improved them; and with a few hundreds lines of additional code, we achieved the dream: support for different dialects (such as Apache-specific XMLRPC extensions), built-in conversion between python exceptions and hierarchical error codes, separate handling of functional and technical errors, auto-retries for the latter, relevant logging and stats before/after requests, thorough validation of input data…
我们针对这些协议的第一批服务器和客户端非常基础,有限,脆弱。 但是逐渐地,我们改进了它们; 并通过几百行附加代码,我们实现了梦想:支持不同的方言(例如Apache特定的XMLRPC扩展),python异常和分层错误代码之间的内置转换,对功能和技术错误的单独处理,自动-后者重试,请求之前/之后的相关日志记录和统计信息,输入数据的全面验证...
Now we were able to robustly connect to any such API, with just a few lines of code.
现在,我们只需几行代码就可以牢固地连接到任何此类API。
Now we were able to expose any set of functions to a wide audience, to servers and to web browsers, with a few decorators and doc updates.
现在,我们有了一些装饰器和文档更新,就可以向广泛的受众,服务器和Web浏览器公开任何功能。
And when it came to communicating between our different applications (microservice-style), it was a job for our system administrator; software-side, it was almost transparent.
当涉及到我们不同应用程序之间的通信(微服务风格)时,这对于我们的系统管理员而言是一项工作; 在软件方面,它几乎是透明的。
Then came REST. REpresentational State Transfer.
然后是REST。 代表性国家转移。
A wave of renewal shook the foundations of inter-services communication.
一波更新动摇了跨服务通信的基础。
RPC was dead, the future was RESTful: resources living each on its own URL, and manipulated exclusively through HTTP protocol.
RPC死了,未来是RESTful的:资源生活在各自的URL上,并且只能通过HTTP协议进行操作。
From then on, every API we had to expose or consume became a new challenge; not to say a testimony to insanity.
从那时起,我们必须公开或使用的每个API都成为了新的挑战。 更不用说精神错乱了。
A short example is worth a long talk. Here is a small API, with data types removed for readability.
一个简短的例子值得一谈。 这是一个小型API,已删除数据类型以提高可读性。
createAccount(username, contact_email, password) -> account_id
addSubscription(account_id, subscription_type) -> subscription_id
sendActivationReminderEmail(account_id) -> null
cancelSubscription(subscription_id, reason, immediate=True) -> null
getAccountDetails(account_id) -> {full data tree}
Just add a properly documented hierarchy of exceptions (InvalidParameterError, MissingParameterError, WorkflowError…), with subclasses to identify important cases (eg. AlreadyExistingUsernameError), and you’re good to go.
只需添加一个正确记录的异常层次结构(InvalidParameterError,MissingParameterError,WorkflowError ...),并使用子类来标识重要的情况(例如AlreadyExistingUsernameError),您就可以开始工作了。
This API is easy to understand, easy to use, and robust. It is backed by a precise state machine, but the restricted set of available operations keeps users away from nonsensical interactions (like changing the creation date of an Account).
该API易于理解,易于使用且功能强大。 它由一个精确的状态机支持,但是可用操作的限制集使用户远离不必要的交互(例如更改帐户的创建日期)。
Estimated time to expose this API as a simple RPC service: a few hours.
将这个API公开为简单RPC服务的预计时间:几个小时。
Ok, now time to go the RESTful way.
好的,现在该走REST风格了。
No more standards, no more precise specifications. Just a vague “RESTful philosophy”, prone to endless metaphysical debates, and as many ugly workarounds.
没有更多的标准,没有更精确的规格。 只是模糊的“ RESTful哲学”,容易发生无休止的形而上学辩论,以及许多丑陋的解决方法。
How do you map the precise functions above, to a handful of CRUD operations? Is sending the activation reminder email an update on a “must_send_activation_reminder_email” attribute? Or the creation of a “activation_reminder_email resource”? Is it sensible to use DELETE for cancelSubscription() if the subscription remains alive during a grace period, and may be resurrected during that time? How do you split the data tree of getAccountDetails() between endpoints, to respect the data model of REST?
您如何将上述精确功能映射到少数CRUD操作? 向激活提醒电子邮件发送有关“ must_send_activation_reminder_email”属性的更新吗? 还是创建“ activation_reminder_email资源”? 如果在宽限期内订阅仍处于活动状态并且可以在该时间内重新启用,对DELETESubscribe()使用DELETE是否明智? 如何在端点之间拆分getAccountDetails()的数据树,以尊重REST的数据模型?
What URL endpoint do you assign to each of your “resources”? Yeah it’s easy, but it has to be done anyway.
您将哪个URL端点分配给每个“资源”? 是的,这很容易,但是无论如何都必须这样做。
How do you express the diversity of error conditions, using the very limited bunch of HTTP codes?
您如何使用非常有限的HTTP代码来表达错误条件的多样性?
What serialization formats, which specific dialects do you use for input and output payloads?
您将哪些序列化格式以及特定的方言用于输入和输出有效载荷?
How exactly do you scatter these simple signatures between HTTP method, URL, query string, payload, headers, and status code?
您如何将这些简单的签名准确地分散在HTTP方法,URL,查询字符串,有效负载,标头和状态代码之间?
And you’re gone for hours, reinventing the wheel. Not even a tailored, smart wheel. A broken and fragile wheel, requiring tons of documentation to be understood, and violating specifications without even knowing it.
而您走了几个小时,重新发明了轮子。 甚至没有量身定制的智能车轮。 破碎的车轮易碎,需要理解大量文档,并且甚至不了解其规格。
How come REST means so much WORK? This is both a paradox, and a shameless pun.
REST如何意味着这么多的工作? 这既是悖论,又是无耻的双关语。
Let’s dive further into the artificial problems born from this design philosophy.
让我们进一步探讨这种设计理念带来的人为问题。
BEWARE : through this document, you’ll encounter lots of semi-rhetorical technical questions. Do not misunderstand them, they DO NOT mean that RESTish webservices can’t solve these problems. They just mean that users have an extra burden of decisions to take, of extensions to integrate, of custom workarounds to apply, and this is a problem in itself.
注意:通过本文档,您将遇到许多半修辞性的技术问题。 不要误解它们,它们并不意味着RESTish Web服务无法解决这些问题。 它们只是意味着用户要承担决策,集成扩展,应用自定义解决方法的额外负担,这本身就是一个问题。
Rest is not CRUD, its advocates will ensure that you don’t mix up these two. Yet minutes later they will rejoice that HTTP methods have well defined semantics to create (POST), retrieve (GET), update (PUT/PATCH) and delete (DELETE) resources.
休息不是CRUD,它的倡导者将确保您不要混淆这两者。 几分钟后,他们将为HTTP方法具有定义良好的语义以创建(POST),检索(GET),更新(PUT / PATCH)和删除(DELETE)资源感到高兴。
They’ll delight in professing that these few “verbs”are enough to express any operation. Well, of course they are; the same way that a handful of verbs would be enough to express any concept in English: “Today I updated my CarDriverSeat with my body, and created an EngineIgnition, but the FuelTank deleted itself”; being possible doesn’t make it any less awkward. Unless you’re an admirator of the Toki Pona language.
他们会很高兴地宣称这几个“动词”足以表达任何操作。 好吧,他们当然是。 少数动词足以用英语表达任何概念的方式相同:“今天,我用身体更新了CarDriverSeat,并创建了EngineIgnition,但是FuelTank删除了自身”; 成为可能并不会因此变得尴尬。 除非您是Toki Pona语言的拥护者。
If the point is to be minimalist, at least let it be done right. Do you know why PUT, PATCH, and DELETE have never been implemented in web browser forms? Because they are useless and harmful. We can just use GET for read and POST for write. Or POST exclusively, when HTTP-level caching is unwanted. Other methods will at best get in your way, at worst ruin your day.
如果要做到极简主义,至少要让它做对。 您知道为什么从未在Web浏览器表单中实现PUT,PATCH和DELETE吗? 因为它们是无用的和有害的。 我们可以只使用GET进行读取,而POST进行写入。 如果不需要HTTP级别的缓存,则排它或POST。 其他方法充其量会妨碍您,最糟糕的是会破坏您的一天。
You want to use PUT to update your resource? OK, but some Holy Specifications state that the data input has to be equivalent to the representation received via a GET. So what do you do with the numerous read-only parameters returned by GET (creation time, last update time, server-generated token…)? You omit them and violate the PUT principles? You include them anyway, and expect an “HTTP 409 Conflict” if they don’t match server-side values (forcing you to then issue a GET...)? You give them random values and expect servers to ignore them (the joy of silent errors)? Pick your poison, REST clearly has no clue what a read-only attribute it, and this won’t be fixed anytime soon. Meanwhile, a GET is dangerously supposed to return the password (or credit card number) which was sent in a previous POST/PUT; good luck dealing with such write-only parameters too.
您要使用PUT更新资源吗? 可以,但是一些神圣规范指出,数据输入必须与通过GET接收的表示形式相同。 那么,您如何处理GET返回的众多只读参数(创建时间,上次更新时间,服务器生成的令牌…)? 您忽略它们并违反了PUT原则吗? 无论如何,您都将它们包括在内,并且如果它们与服务器端的值不匹配(会迫使您随后发出GET ...),您会期望“ HTTP 409冲突”吗? 您给它们提供随机值,并希望服务器忽略它们(无声错误的乐趣)? 选择您的毒药,REST显然不知道它是什么只读属性,并且不会很快得到解决。 同时,GET危险地返回在先前的POST / PUT中发送的密码(或信用卡号)。 也好运气处理这样的只写参数。
Did I forget to mention that PUT also brings dangerous race conditions, where several clients will override each other’s changes, whereas they just wanted to update different fields?
我是否忘记提及PUT还带来了危险的竞争条件,即几个客户端将覆盖彼此的更改,而他们只是想更新不同的字段?
You want to use PATCH to update your resource? Nice, but like 99% of people using this verb, you’ll just send a subset of resource fields in your request payload, hoping that the server properly understands the operation intended (and all its possible side effects); lots of resource parameters are deeply linked or mutually exclusive(ex. it’s either credit card OR paypal token, in a user’s billing info), but RESTful design hides this important information too. Anyway, you’d violate specs once more: PATCH is not supposed to just send a bunch of fields to be overridden. Instead, you’re supposed to provide a “set of instructions” to be applied on the resources. So here you go again, take your paperboard and your coffee mug, you’ll have to decide how to express these instructions. Often with handcrafted specifications, since Not-Invented-Here Syndrome is a de-facto standard in the REST world. (Edit: REST advocates have backpedaled on this subject, with Json Merge Patch, an alternative to formats like Json Patch)
您要使用PATCH更新资源吗? 很好,但是像99%的使用此动词的人一样,您只需在请求有效负载中发送资源字段的子集,希望服务器正确理解预期的操作(及其所有可能的副作用); 许多资源参数是紧密链接或相互排斥的(例如,在用户的帐单信息中是信用卡或Paypal令牌),但是RESTful设计也隐藏了这一重要信息。 无论如何,您将再次违反规范:PATCH不应仅发送一堆要覆盖的字段。 相反,您应该提供一个“指令集”以应用于资源。 因此,在这里您再次去,拿走纸板和咖啡杯,您必须决定如何表达这些指示。 由于Not-Invented-Here Syndrome是REST世界中的事实上的标准,因此通常具有手工制定的规范。 (编辑:REST倡导者通过Json Merge Patch替代了Json Patch之类的格式,在这个问题上退缩了)
You want to DELETE resources? OK, but I hope you don’t need to provide substantial context data; like a PDF scan of the termination request from the user. DELETE prohibits having a payload. A constraint that REST architects often dismiss, since most webservers don’t enforce this rule on the requests they receive. How compatible, anyway, would be a DELETE request with 2 MBs of base64 query string attached? (Edit: the RFC 2616, indicating that payloads without semantics should be ignored, is now obsolete)
您要删除资源吗? 好的,但是我希望您不需要提供大量的上下文数据; 例如来自用户的终止请求的PDF扫描。 DELETE禁止具有有效负载。 REST架构师经常会忽略此约束,因为大多数Web服务器不会对收到的请求执行此规则。 无论如何,带有2 MB的base64查询字符串的DELETE请求将如何兼容? (编辑: RFC 2616指示无语义的有效负载现在已过时)
REST aficionados easily profess that “people are doing it wrong” and their APIs are “actually not RESTful”. For example, lots of developers use PUT to create a resource directly on its final URL (/myresourcebase/myresourceid), whereas the “good way” (edit: according to many) of doing it is to POST on a parent URL (/myresourcebase), and let the server indicate, with an HTTP “Location” header, the new resource’s URL (edit: it’s not an HTTP redirection though). The good news is: it doesn’t matter. These rigorous principles are like Big Endian vs Little Endian, they occupy philosophers for hours, but have very little impact on real life problems, i.e “getting stuff done”.
REST爱好者 轻易地宣称“人们做错了”,而他们的API“实际上不是RESTful”。 例如,许多开发人员使用PUT直接在其最终URL( / myresourcebase / myresourceid )上创建资源,而这样做的“好方法”(根据许多人的说法是编辑)是在父URL( / myresourcebase )上进行POST。 ),然后让服务器使用HTTP“ Location”标头指示新资源的URL(编辑:虽然它不是HTTP重定向)。 好消息是:没关系。 这些严格的原则就像Big Endian与Little Endian一样,它们占据了哲学家数小时之久,但对现实生活中的问题(即“把事情做好”)的影响很小。
By the way… handcrafting URLs is always great fun. Do you know how many implementations properly urlencode() identifiers while building REST urls? Not that many. Get ready for nasty breakages and SSRF/CSRF attacks.
顺便说一下,手工制作URL总是很有趣。 您知道在构建REST URL时有多少种实现正确地urlencode()标识符吗? 不是很多 准备好应对令人讨厌的破坏和SSRF / CSRF攻击。
About every coder is able to make a “nominal case” work. Error handling is one of these features which will decide if your code is robust software, or a huge pile of matchsticks.
几乎每个编码人员都可以进行“名义上的工作”。 错误处理是这些功能之一,它将决定您的代码是可靠的软件还是大量的火柴。
HTTP provides a list of error codes out-of-the-box. Great, let’s see that.
HTTP提供了现成的错误代码列表。 太好了,让我们看看。
Using “HTTP 404 Not Found” to notify about an unexisting resource sounds RESTful as heck, doesn’t it? Too bad: your nginx was misconfigured for 1 hour, so your API consumers got only 404 errors and purged hundreds of accounts, thinking they were deleted….
使用“未找到HTTP 404”来通知不存在的资源听起来像RESTful,不是吗? 太糟糕了:您的nginx配置错误1小时,因此您的API使用者仅收到404错误并清除了数百个帐户,以为它们已被删除……。
Using “HTTP 401 Unauthorized” when a user doesn’t have access credentials to a third-party service sounds acceptable, doesn’t it? However, if an ajax call in your Safari browser gets this error code, it might startle your end customer with a very unexpected password prompt [it did, years ago, YMMV].
当用户无权访问第三方服务的凭据时使用“ HTTP 401未经授权”听起来是可以接受的,不是吗? 但是,如果Safari浏览器中的ajax调用收到此错误代码,它可能会以非常意外的密码提示[您几年前,YMMV]震惊了您的最终客户。
HTTP existed long before “RESTful webservices”, and the web ecosystem is filled with assumptions about the meaning of its error codes. Using them to transport application errors is like using milk bottles to dispose of toxic waste: inevitably, one day, there will be trouble.
HTTP在“ RESTful Web服务”之前就已经存在很久了,Web生态系统充满了关于其错误代码含义的假设。 使用它们来传输应用程序错误就像使用牛奶瓶来处置有毒废物:不可避免地,有一天会出现麻烦。
Some standard HTTP error codes are specific to Webdav, others to Microsoft, and the few remaining have definitions so fuzzy that they are of no help. In the end, like most REST users, you’ll probably use random HTTP codes, like “HTTP 418 I’m a teapot” or unassigned numbers, to express your application-specific exceptions. Or you’ll shamelessly return “HTTP 400 Bad Request” for all functional errors, and then invent your own clunky error format, with booleans, integer codes, slugs, and translated messages stuffed into an arbitrary payload. Or you’ll give up altogether on proper error handling; you’ll just return a plain message, in natural language, and hope that the caller will be a human able to analyze the problem, and take action. Good luck interacting with such APIs from an autonomous program.
一些标准的HTTP错误代码特定于Webdav,而其他一些则特定于Microsoft,而其余的则具有模糊的定义,以至于无济于事。 最后,像大多数REST用户一样,您可能会使用随机HTTP代码(例如“ HTTP 418我是茶壶”或未分配的数字)来表示您的应用程序特定的异常。 否则,您将无耻地返回“ HTTP 400错误请求”以获取所有功能错误,然后发明自己的笨拙错误格式,将布尔值,整数代码,段代码和已翻译的消息填充到任意有效载荷中。 否则,您将完全放弃适当的错误处理; 您将以自然语言返回一条简单的消息,并希望呼叫者将是能够分析问题并采取行动的人。 与自治程序中的此类API交互的好运。
REST has made a career out of boasting about concepts that any service architect in his right mind already respects, or about principles that it doesn’t even follow. Here are some excerpts, grabbed from top-ranked webpages.
REST的职业是吹嘘自己正确的想法已经尊重任何服务架构师的观念,或者吹嘘甚至不遵循的原则。 以下是摘录自排名最高的网页的摘录。
REST is a client-server architecture. The client and the server both have a different set of concerns. What a scoop in the software world.
REST是一种客户端-服务器体系结构。 客户端和服务器都有不同的关注点。 在软件界真是个独家新闻。
REST provides a uniform interface between components. Well, like any other protocol does, when it’s enforced as the lingua franca of a whole ecosystem of services.
REST在组件之间提供了统一的接口。 好吧,就像其他协议一样,当它作为整个服务生态系统的通用语言执行时,也是如此。
REST is a layered system. Individual components cannot see beyond the immediate layer with which they are interacting. It sounds like a natural consequence of any well designed, loosely coupled architecture; amazing.
REST是一个分层系统。 各个组件无法看到与它们交互的直接层。 这听起来像是任何精心设计的,松散耦合的体系结构的自然结果。 惊人。
Rest is awesome, because it is STATELESS. Yes there is probably a huge database behind the webservice, but it doesn’t remember the state of the client. Or, well, yes, actually it remember its authentication session, its access permissions… but it’s stateless, nonetheless. Or more precisely, just as stateless as any HTTP-based protocol, like simple RPC mentioned previously.
休息真棒,因为它是无状态的。 是的,Web服务背后可能有一个巨大的数据库,但它不记得客户端的状态。 或者,是的,实际上它记住了它的身份验证会话,访问权限……但是它还是无状态的。 或更准确地说,就像任何基于HTTP的协议一样无状态,例如前面提到的简单RPC。
With REST, you can leverage the power of HTTP CACHING! Well here is at last one concluding point: a GET request and its cache-control headers are indeed friendly with web caches. That being said, aren’t local caches (Memcached etc.) enough for 99% of web services? Out-of-control caches are dangerous beasts; how many people want to expose their APIs in clear text, so that a Varnish or a Proxy on the road may keep delivering outdated content, long after a resource has been updated or deleted? Maybe even delivering it “forever”, if a configuration mistake once occurred? A system must be secure by default. I perfectly admit that some heavily loaded systems want to benefit from HTTP caching, but it costs much less to expose a few GET endpoints for heavy read-only interactions, than to switch all operations to REST and its dubious error handling.
借助REST,您可以利用HTTP CACHING的强大功能! 好了,这是最后一个结论点:GET请求及其缓存控制标头确实与Web缓存友好。 话虽这么说,对于99%的Web服务来说,本地缓存(Memcached等)还不够吗? 失控的缓存是危险的野兽。 有多少人想要以明文形式公开其API,以便在更新或删除资源后很长一段时间内,清漆或代理可能继续传递过时的内容? 如果曾经发生配置错误,甚至可以“永远”交付它? 默认情况下,系统必须是安全的。 我完全承认某些重负载系统希望从HTTP缓存中受益,但是暴露一些GET端点以进行大量只读交互的成本要比将所有操作切换到REST及其可疑的错误处理要少得多。
Thanks to all this, REST has HIGH PERFORMANCE! Are we sure of that? Any API designer knows it: locally, we want fine-grained APIs, to be able to do whatever we want; and remotely, we want coarse-grained APIs, to limit the impact of network round-trips. Here is again a domain in which REST fails miserably. The split of data between “resources”, each instance on its own endpoint, naturally leads to the N+1 Query problem. To get a user’s full data (account, subscriptions, billing information…), you have to issue as many HTTP requests; and you can’t parallelize them, since you don’t know in advance the unique IDs of related resources. This, plus the inability to fetch only part of resource objects, naturally creates nasty bottlenecks (edit: yes, you can stuff extensions like Compound/Partial Documents into your setup to help with that)..
由于所有这些,REST具有很高的性能 ! 我们确定吗? 任何API设计人员都知道:在本地,我们希望使用细粒度的API,以便能够执行我们想要的任何事情; 在远程,我们希望使用粗粒度的API,以限制网络往返的影响。 这又是REST严重失败的领域。 每个实例在其自身端点上的“资源”之间的数据拆分自然会导致N + 1查询问题。 要获取用户的完整数据(帐户,订阅,账单信息等),您必须发出尽可能多的HTTP请求; 而且您无法并行化它们,因为您事先不知道相关资源的唯一ID。 这,加上无法仅获取部分资源对象,自然会造成令人讨厌的瓶颈(编辑:是的,您可以将诸如“化合物/部分文档”之类的扩展内容塞入您的设置中以提供帮助)。
REST offers better compatibility. How so? Why do so many REST webservices have “/v2/” or “/v3/” in their base URLs then? Backwards and forward compatible APIs are not hard to achieve, with high level languages, as long as simple rules are followed when adding/deprecating parameters. As far as I know, REST doesn’t bring anything new on the subject.
REST提供了更好的兼容性。 为何如此? 为什么这么多的REST Web服务的基本URL中都有“ / v2 /”或“ / v3 /”? 使用高级语言,向后兼容和向前兼容的API并不难实现,只要添加/弃用参数时遵循简单的规则即可。 据我所知,REST并未带来任何新的变化。
REST is SIMPLE, everyone knows HTTP! Well, everyone knows pebbles too, yet people are happy to have better blocks when building their house. The same way XML is a meta-language, HTTP is a meta-protocol. To have a real application protocol (like “dialects” are to XML), you’ll need to specify lots of things; and you’ll end up with Yet Another RPC Protocol, as if there were not enough already.
REST很简单,每个人都知道HTTP! 嗯,每个人也都知道鹅卵石,但是人们很高兴在建造房屋时拥有更好的砌块。 XML是一种元语言,HTTP是一种元协议。 要拥有一个真正的应用程序协议(例如XML的“方言”),您需要指定很多东西。 并最终获得“另一个RPC协议”,好像还不够。
REST is so easy, it can be queried from any shell, with CURL! OK, actually, every HTTP-based protocol can be queried with CURL. Even SOAP. Issuing a GET is particularly straightforward, for sure, but good luck writing json or xml POST payloads by hand; people usually use fixture files, or, much more handy, full-fledged API clients instantiated directly in the command line interface of their favorite language.
REST非常简单,可以使用CURL从任何shell中查询! 好的,实际上,可以使用CURL查询每个基于HTTP的协议。 甚至是SOAP。 当然,发出GET尤其简单,但是祝您好运,可以手动编写json或xml POST有效负载。 人们通常使用Fixture文件,或者更方便,更完整的API客户端,直接在其喜欢的语言的命令行界面中实例化。
“The client does not need any prior knowledge of the service in order to use it”. This is by far my favourite quote. I’ve found it numerous times, under different forms, especially when the buzzword HATEOAS lurked around; sometimes with some careful (but insufficient) “except” phrases following. Still, I don’t know in which fantasy world these people live, but in this one, a client program is not a colony of ants; it doesn’t browse remote APIs randomly, and then decide how to best handle them, based on pattern recognition or black magic. Quite the opposite; the client has strong expectations on what it means, to PUT this one field to this one URL with this one value, and the server had better respect the semantic which was agreed upon during integration, else all hell might break loose.
“客户不需要任何有关服务的先验知识即可使用它” 。 到目前为止,这是我最喜欢的报价。 我已经以不同的形式无数次找到它,尤其是当流行语HATEOAS潜行时; 有时在后面加上一些小心(但不足)的“除外”短语。 我仍然不知道这些人生活在哪个幻想世界中,但是在这个例子中,客户端程序并不是一群蚂蚁。 它不会随机浏览远程API,然后根据模式识别或黑魔法来决定如何最好地处理它们。 恰恰相反; 客户端对它的含义有很高的期望,将这一字段与该值一起放入该URL,并且服务器最好尊重集成过程中约定的语义,否则可能会变得一团糟。
Forget about the “right” part. REST is like a religion, no mere mortal will ever grasp the extent of its genius, nor “do it right”.
忘记“正确的”部分。 REST就像一种宗教,没有凡人会掌握其天才的范围,也不会“做到正确”。
So the real question is: if you’re forced to expose or consume webservices in a kinda-RESTful way, how to rush through this job, and switch to more constructive tasks asap?
因此,真正的问题是:如果您被迫以某种RESTful方式公开或使用Web服务,那么如何尽快完成这项工作,并尽快切换到更具建设性的任务?
Update: it turns out that there are actually lots of “standards” and industrialization efforts for REST, although I had never encountered them personnally (maybe because few people use them?). More information in my follow-up article.
更新 :事实证明,尽管我从未亲自遇到过REST(实际上是因为很少有人使用它们),但是REST实际上有很多“标准”和工业化方面的努力。 有关更多信息,请参见我的后续文章 。
Each web framework has its own way of defining URL endpoint. So expect some big dependencies, or a good layer of handwritten boilerplate, to plug your existing API onto your favorite server as a set of REST endpoint.
每个Web框架都有其自己的定义URL端点的方式。 因此,请期待一些较大的依赖项或好的手写样板层,以将您的现有API作为一组REST端点插入到您喜欢的服务器上。
Libraries like Django-Rest-Framework automate the creation of REST APIs, by acting as data-centric wrappers above SQL/noSQL schemas. If you just want to make “CRUD over HTTP”, you could be fine with them. But if you want to expose common “do-this-for-me” APIs, with workflows, constraints, complex data impacts and such, you’ll have a hard time bending any REST framework to fit your needs.
像Django-Rest-Framework这样的库通过充当SQL / noSQL模式之上的以数据为中心的包装器,自动创建REST API。 如果您只想制作“ HTTP上的CRUD”,可以使用它们。 但是,如果您想要公开常见的“为我做” API,以及工作流,约束,复杂的数据影响等,那么将很难调整任何REST框架来满足您的需求。
Be prepared to connect, one by one, each HTTP method of each endpoint, to the corresponding method call; with a fair share of handmade exception handling, to translate passing-through exceptions into corresponding error codes and payloads.
准备将每个端点的每个HTTP方法一个接一个地连接到相应的方法调用; 与相当一部分手工异常处理一起,将传递的异常转换为相应的错误代码和有效负载。
From experience, my guess is: you don’t.
根据经验,我的猜测是:您不会。
For each API integration, you’ll have to browse lengthy docs, and follow detailed recipes on how each of the N possible operations has to be performed.
对于每个API集成,您都必须浏览冗长的文档,并按照详细的食谱说明如何执行N种可能的操作。
You’ll have to craft URLs by hand, write serializers and deserializers, and learn how to workaround the ambiguities of the API. Expect quite some trial-and-error before you tame the beast.
您将需要手工制作URL,编写序列化器和反序列化器,并学习如何解决API的歧义。 在驯服野兽之前,请期待一些反复试验。
Do you know how webservices providers make up for this, and ease adoption?
您知道网络服务提供商如何弥补这一点并简化采用过程吗?
Simple, they write their own official client implementations.
很简单,他们编写自己的官方客户端实现。
FOR. EVERY. MAJOR. LANGUAGE. AND. PLATFORM.
对于。 每个。 重大的。 语言。 和。 平台。
I’ve recently dealt with a subscription management system. They provide clients for PHP, Ruby, Python, .NET, iOS, Android, Java… plus some external contributions for Go and NodeJS.
我最近处理了订阅管理系统。 他们为PHP,Ruby,Python,.NET,iOS,Android,Java等提供客户端,此外还为Go和NodeJS提供了一些外部支持。
Each client lives in its own Github repository. Each with its own big list of commits, bug tracking tickets, and pull requests. Each with its own usage examples. Each with its own awkward architecture, somewhere between ActiveRecord and RPC proxy.
每个客户都住在自己的Github存储库中。 每个都有自己的大型提交列表,错误跟踪票证和拉取请求。 每个都有自己的用法示例。 每个都有自己笨拙的体系结构,介于ActiveRecord和RPC代理之间。
This is astounding. How much time is spent developing such weird wrappers, instead of improving the real, the valuable, the getting-stuff-done, webservice?
这太惊人了。 花了多少时间开发这种奇怪的包装程序,而不是改进真正的,有价值的,渐渐完成的Web服务?
For decades, about every programming language has functioned with the same workflow: sending inputs to a callable, and getting results or errors as output. This worked well. Quite well.
几十年来,几乎每种编程语言都具有相同的工作流程:将输入发送到可调用对象,并将结果或错误作为输出。 这很好。 很好。
With Rest, this has turned into an insane work of mapping apples to oranges, and praising HTTP specifications to better violate them minutes later.
使用Rest,这变成了将苹果映射到桔子的疯狂工作,并称赞HTTP规范在几分钟后更好地违反了它们。
In an era where MICROSERVICES are more and more common, how come such an easy task — linking libraries over networks — remains so artificially crafty and cumbersome?
在MICROSERVICES越来越普遍的时代,如此简单的任务-通过网络链接库-为何仍然如此人为地狡猾且繁琐?
I don’t doubt that some smart people out there will provide cases where REST shines; they’ll showcase their homemade REST-based protocol, allowing to discover and do CRUD operation on arbitrary object trees, thanks to hyperlinks; they’ll explain how the REST design is so brilliant, that I’ve just not read enough articles and dissertations about its concepts.
我毫不怀疑有些聪明的人会提供REST令人瞩目的案例。 他们将展示他们自己的基于REST的协议,借助超链接,可以发现和执行任意对象树上的CRUD操作。 他们将解释REST设计的出色之处,以至于我还没有阅读足够的文章和有关其概念的论文。
I don’t care. Trees are recognized by their own fruits. What took me a few hours of coding and worked very robustly, with simple RPC, now takes weeks and can’t stop inventing new ways of failing or breaking expectations. Development has been replaced by tinkering.
我不在乎 树木被自己的果实所识别。 我花了几个小时编写代码,并使用简单的RPC进行了非常稳健的工作,现在花费了数周的时间,并且不能停止发明失败或破坏期望的新方法。 修补已取代了发展。
Almost-transparent remote procedure call was what 99% people really needed, and existing protocols, as imperfect as they were, did the job just fine. This mass monomania for the lowest common denominator of the web, HTTP, has mainly resulted in a huge waste of time and grey matter.
几乎透明的远程过程调用是99%的人真正需要的,并且现有的协议(尽管不完善)可以很好地完成工作。 这种用于网络的最低公分母的质量单调症主要导致时间和灰质的巨大浪费。
REST promised simplicity and delivered complexity.REST promised robustness and delivered fragility.REST promised interoperability and delivered heterogeneity.REST is the new SOAP.
REST保证了简单性并带来了复杂性。 REST保证了其健壮性和脆弱性。 REST保证了互操作性并提供了异构性。 REST是新的SOAP。
The future could be bright. There are still tons of excellent protocols available, in binary or text format, with or without schema, some leveraging the new abilities of HTTP2… so let’s move on, people. We can’t forever remain in the Stone Age of Webservices.
未来可能是光明的。 仍然有成百上千的优秀协议可用,无论是二进制还是文本格式,带有或不带有模式,都可以利用HTTP2的新功能……让我们继续吧。 我们不能永远停留在Web服务的石器时代。
Edit: many people asked for these alternative protocols, the subject would deserve its own story, but one could have a look at XMLRPC and JSONRPC (simple but quite relevant), or JSONWSP (includes schemas), or language-specific layers like Pyro or RMI when for internal use, or new kids in the block like GraphQL and gRPC for public APIs…
编辑 :许多人要求使用这些替代协议,该主题应该得到其应有的报道,但您可以看看XMLRPC和JSONRPC(简单但非常相关),JSONWSP(包括模式)或特定于语言的层(例如Pyro或供内部使用的RMI,或用于公共API的GraphQL和gRPC之类的新手……
Edited on December 12, 2017:
于2017年12月12日编辑:
Edited on December 28, 2017:
于2017年12月28日编辑:
Edited on January 7, 2018
于2018年1月7日编辑
Edited on January 19, 2018
于2018年1月19日编辑
Edited on January 19, 2018
于2018年1月19日编辑
Edited on February 2, 2018
于2018年2月2日编辑
Edited on April 14, 2019
于2019年4月14日编辑
Edited on July 6, 2019
于2019年7月6日编辑
Please leave your comments below. And here are past comments about this article on Medium: https://medium.com/p/97ff6c09896d/responses/show
请在下方留下你的意见。 以下是有关这篇文章在媒体上的过往评论: https : //medium.com/p/97ff6c09896d/responses/show
翻译自: https://www.freecodecamp.org/news/rest-is-the-new-soap-97ff6c09896d/
soap rest