在尝试使用REST架构风格重新设计现有应用程序时,我遇到了一个问题,我想将其称为“Mediatype Explosion”。但是,我不确定这是否真的是REST的问题或固有的好处。为了解释我的意思,请采用以下示例
我们的应用程序的一小部分看起来像:
资源集合的-collections->集合-的-物品─>项
,即顶级是集合的集合,这些集合中的每一个都是项目的集合。
此外,每个项目都有8个属性,可以单独读取和写入。尝试将上述层次结构公开为RESTful资源会让我看到以下媒体类型:
application/vnd.mycompany.collection-of-collections+xml
application/vnd.mycompany.collection-of-items+xml
application/vnd.mycompany.item+xml
此外,由于每个项目有8个属性可以单独读取和写入,因此将产生另外8种媒体类型。例如一个项目的“值”属性的这种媒体类型将是:
application/vnd.mycompany.item_value+xml
正如我之前提到的,这只是我们应用程序的一小部分,我希望以这种方式暴露几个不同的集合和项目。
我的问题是:
我也知道上面的设计是高度精细的,特别是暴露项目的各个属性,并为每个属性分别设置媒体类型。然而,使其粗糙意味着我将最终通过线路传输不必要的数据,而实际上客户端只需要读取或写入项目的单个属性。你会如何处理这样的设计问题?
答案 0 :(得分:32)
减少所需媒体类型数量的一种方法是使用定义的媒体类型来保存其他媒体类型的列表。这可以用于您的所有收藏。通常,列表往往具有一致的行为集。 您可以滚动自己的vnd.mycompany.resourcelist,也可以重用Atom collection之类的内容。
对于像vnd.mycompany.item这样的特定资源表示,您可以做的事情很大程度上取决于您客户的特征。它在浏览器中吗?你可以做代码下载吗?您的客户端是丰富的UI,还是数据处理客户端?
如果客户端要进行特定的数据处理,那么您几乎需要坚持使用精确的媒体类型,最终可能会有大量的媒体类型。但从好的方面来看,如果您使用SOAP,那么媒体类型将少于命名空间!
请记住,媒体类型是您的合同,如果您的应用程序需要与客户定义大量合同,那么就这样吧。
但是,我不会定义合同来交换单个属性值。如果您觉得有必要这样做,那么您在设计中做了其他错误。分布式界面设计需要进行冗长的对话,而不是繁琐的对话。
答案 1 :(得分:30)
我想我终于得到了Ian Robinson's presentation对上述问题的澄清,并认为我应该在这里分享。
最近,我在Jim Webber的博客条目中发现了“ 媒体类型,用于帮助调整超媒体引擎,结构架构 ”。然后,我通过Thoughtworks的presentation找到了这个Ian Robinson。这个演示文稿是我遇到的最好的演示文稿之一,它提供了对媒体类型和模式语言的角色和职责的非常清楚的理解(整个演示文稿是一种享受,我强烈建议所有人)。特别注意标题为“你已经选择了应用程序/ xml,你是 st rd”的幻灯片。和“自定义媒体类型”。 Ian清楚地解释了模式和媒体类型的不同角色。简而言之,这是我对伊恩的演讲的看法:
媒体类型描述包括标识超媒体控件的处理模型,并定义适用于该类型资源的方法。识别超媒体控制意味着“我们如何识别链接?”在XHTML中,链接是基于标记识别的,RDF具有不同的语义。媒体类型有助于识别的下一件事是什么方法适用于给定媒体类型的资源?一个很好的例子是ATOM(application / atom + xml)规范,它提供了对超媒体控件的非常丰富的描述;他们告诉我们链接元素是如何定义的?以及当我们取消引用URI时我们可以期望能够做到的事情,因此它实际上讲述了我们可以期望能够应用于资源的方法。资源表示的结构信息是媒体类型描述中包含的 NOT 部分或 NOT ,但作为实际表示的适当模式的一部分提供,即媒体类型规范不一定会对代表的结构作出任何规定。
那么这对我们意味着什么?简单地说,我们不需要单独的媒体类型来描述每个资源,如上面我原来的问题所述。我们只需要一种媒体类型用于整个应用程序。这可能是一种全新的自定义媒体类型或自定义媒体类型,它可以重复使用现有的标准媒体类型,或者更好,只是一种标准媒体类型,可以在我们的应用程序中重复使用而无需重复使用。
希望这有帮助。
答案 2 :(得分:7)
在我看来,这是REST概念的薄弱环节。作为一种建筑和界面风格,REST非常出色,Roy F.和其他人所做的工作大大提升了现有技术水平。但是标准媒体类型可以传达(不仅仅是代表)的内容存在上限。
要让人们理解并使用您的REST-ish API,他们需要了解数据的含义。有些媒体类型可以讲述大部分故事的API;例如如果你有一个文本到语音API,输入媒体类型是text / plain,输出媒体类型是audio / mp4,那么熟悉这个主题的人可能会做。文本输入,音频输出,可能足以在这种情况下继续。
但是很多API只能用媒体类型来传达它们的意义。假设您有一个处理航空公司票务的API。输入和输出主要是数据。每个API的输入和输出上的媒体类型可以是application / json或application / xml,因此媒体类型不会传输大量信息。那么你会看看输入和输入中的各个字段。输出。也许有一个叫“价格”的领域。这是美元还是便士?美元还是其他一些货币?我不知道如果没有(a)非常具有描述性的名称(如“price_pennies_in_usd”)或(b)文档,用户将如何回答这些问题。更不用说格式约定了。是否提供带破折号的帐号,必须是全字母等字母。没有标准媒体类型可以定义这些问题。
当我们遇到客户端不需要对数据进行语义理解的情况时,这是一回事。这很好用。浏览器可以直观地呈现任何兼容文档,并与任何兼容资源进行交互这一事实非常棒。这基本上就是“媒体”用例。
但是当客户端(或实际上是客户端背后的开发人员/用户)需要理解数据的语义时,情况就完全不同了。 数据不是媒体 。除了记录数据外,没有办法解释数据的所有真实含义和细微之处。这是“数据”用例。
REST的过度学术定义适用于媒体用例。它不起作用,需要补充非纯粹但有用的东西,如文档,用于其他用例。
答案 3 :(得分:1)
您正在使用媒体类型来传达应存储在表示中的数据的详细信息。所以你可以只有一种媒体类型,比如说“application / xml”,然后你的XML表示就像:
<collection-of-collections>
<collection-of-items>
<item>
</item>
<item>
</item>
</collection-of-items>
<collection-of-items>
<item>
</item>
<item>
</item>
</collection-of-items>
</collection-of-collections>
如果您担心发送过多数据,请将JSON替换为XML。另一种节省写入和读取字节的方法是使用gzip编码,这可以减少约60-70%的内容。除非您有超高性能需求,否则其中一种方法应该适合您。 (为了获得更好的性能,您可以使用非常简洁的手工制作的字符串,甚至可以下载到自定义的二进制TCP / IP协议。)
修改您关注的一点是:
使[表示]粗略意味着我将最终通过线路传输不必要的数据,而实际上客户端只需要读取或写入项目的单个属性
在任何Web服务中,发送消息都会产生大量开销(每个HTTP请求可能需要几百个字节用于起始行和请求标头,并且与this example中的每个HTTP响应相同)。因此,通常您希望具有更少的粒度表示。所以你会编写你的客户端来请求这些更大的表示,然后将它们缓存在一些方便的内存数据结构中,你的程序可以从中读取数据多次(但一定要遵守服务器设置的HTTP到期日期)。将数据写入服务器时,通常会将 set 的更改组合到内存数据结构中,然后将更新作为单个HTTP PUT请求发送到服务器。
你应该抓一本Richardson和Ruby的RESTful Web Services,这是一本关于如何设计REST网络服务的真正优秀的书,并且比我能更清楚地解释事情。如果你在Java工作,我强烈推荐RESTlet框架,它非常忠实地模拟REST概念。罗伊菲尔丁定义REST原则的USC dissertation也可能有所帮助。
答案 4 :(得分:1)
应该很少创建媒体类型,并且应该投入时间来确保格式能够在更改后继续存在。
当您依赖xml时,如果在一个源中描述了媒体类型,则无法创建一种媒体类型。
选择ATOM而不是拥有一个支持多个根元素的主机媒体类型并不一定会带给您任何东西:在决定是否存在足够的信息进行处理之前,您仍需要在特定操作的上下文中开始阅读消息请求。
所以我建议您可以愉快地使用一种媒体类型,由一个根元素表示,并使用模式语言来指定可以包含哪些元素。
换句话说,像xsd这样的语言可以让您输入媒体类型以支持多个根元素之一。 application / vnd.acme.humanresources + xml没有任何内在错误,它描述了一个可以作为根元素的xml文档。
因此,要回答您的问题,请创建尽可能少的媒体类型,方法是质疑您在媒体类型的文档中放入的内容是否可供开发人员理解和实施。
答案 5 :(得分:0)
除非您打算注册这些媒体类型,否则您应选择其中一个existing mime types,而不是尝试构建自己的格式。正如Jim提到application/xml or text/xml或application/json适用于REST设计中传输的大部分内容。
在这里回复达雷尔是Roy's full post。您是不是要通过创建自己的mime类型来定义类型化资源?
Suresh,为什么不是HTTP + POX Restful?