2012-03-15 63 views
2

我有一个服务需要.odt模板文件和一些文本值,并在输出时生成.odt。我需要通过HTTP使这项服务可用,而我不知道什么是使RESTful界面工作的最有效途径。通过HTTP模拟过程调用的最佳/最RESTful方式是什么?

我需要能够提供的模板文件,并输入值,服务器 - 并获得所产生的.odt文件发回给我。我看到这是如何工作的选项有:

  1. PUT或POST模板到服务器,然后做一个GET请求,沿着我刚刚发布模板的URI传递,再加上输入值 - 将GET响应主体将拥有.odt
  2. 在单个GET请求中发送模板和参数 - 模板文件将进入GET请求主体。
  3. 像上面的(2)一样,除了做整个事情作为单个POST请求而不是GET。

(1)的问题是我不想将模板文件存储在服务器上。这增加了复杂性,并且除了它是一种非常REST风格的方法之外,存储该文件对我来说没有用处。另外,一个请求会比2更好,所有其他事情都是平等的。

与(2)是把身体的GET请求接壤HTTP的滥用问题 - 这是我现在使用的软件支持,但不一定是。

数字(3)似乎有误导性,因为这比'发布'更自然地是'读取'或'获取'操作。我正在做的事情本质上就像一个函数调用 - 我需要在中传递大量的数据,而且我真的只是使用HTTP作为在网络上公开我的代码的便捷方式。也许我想要做的事情本质上不是RESTful,并且没有REST友好的解决方案?任何人都可以建议吗?谢谢!

+0

刚刚发现了一个非常尖锐的问题,解决(但不回答)我的问题:http://stackoverflow.com/questions/9010724/rest-and-get-again-这似乎是我的问题的症结所在 - 为什么我们是否应该能够提供复杂/大型数据作为GET请求的一部分? – 2012-03-15 20:13:12

回答

1

你在做什么不是休息-FUL - 或者,至少,是很难在REST来表达,因为你都在思考的操作第一,不是第一对象。

最REST-ful表达式是创建一个新的“OdtTemplate”资源(或获取现有URI的资源),创建一个新的“SetOfValues”资源,然后创建一个与其绑定的“FillInTemplateWithValues”作业资源输入到这两个输入中,并且可以读取它们以确定作业的状态,并获取指向包含结果的最终“FilledInDocument”对象的指针。

REST是关于创建,读取,更新和销毁对象的全部内容。如果您不能将您的流程建模为CRUD数据库,则它不是REST。这意味着您需要将模板存储在服务器上。

尽管实现RPC over HTTP模型,然后提交模板和值,然后同步获取响应 - 或者您指定的其他非REST模式之一,您可能会更好......因为这是正是你想要的。

+0

我不同意“REST全部关于CRUD”。虽然看起来在CRUD(创建,读取,更新,删除)中有四个REST方法(GET,PUT,POST,DELETE)和四个操作,但声称操作是并行的,这是一个逻辑上的跳跃。请参阅[REST APIs必须由超文本驱动](http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven)和[Crud对于休息不好](http:// soa .dzone.com /新闻/ CRUD坏休息)。 – 2012-08-11 22:26:07

0

如果在存储模板没有价值,然后选择2是最平安,但你知道有让您的GET主体上降落的可能性。

不过,如果我是这个系统的用户,我会觉得很浪费必须每次我想和值来填充它上传模板。相反,将模板存储并允许具有不同值的不同请求填充生成的文档似乎更合适。

5

哇,所以这个答案迅速升级...

在过去一年左右的时间我已经尝试通过书籍,邮件列表等出于某种原因,我决定,以获得更好地了解REST的选择你的问题作为我所学到的东西的测试。

对不起:P


让我们把这个整个例子一步简单。不用担心用户上传文件,我们会假设用户只是传递一个字符串。所以,实际上,除了要替换的字符参数(键/值列表)外,他们还要传递一个字符串。稍后我们将处理文件上传部分。

这是一个RESTful的方式,它不需要任何东西存储在服务器上。我将使用一些HTML(尽管破碎,我会忽略像HEAD这样的东西)作为我的媒体类型,只是因为它是相当知名的。

样本解决方案

首先,用户需要访问我们的REST服务。

GET/

<body> 
    <a rel="http://example.com/rels/arguments" href="/arguments"> 
     Start Building Arguments 
    </a> 
</body> 

这基本上为用户提供了一种方式来真正开始对我们的服务进行交互。现在他们只有一个选项:使用链接来构建一组新的参数(最终将用于字符串替换方案中的名称/值对)。所以用户去那个链接。

GET /参数

<body> 
    <a rel="self" href="/arguments"/> 
    <form rel="http://example.com/rels/arguments" method="get" action="/arguments?{key}={value}"> 
     <input id="key" name="key" type="text"/> 
     <input id="value" name="value" type="text"/> 
    </form> 
    <form rel="http://example.com/rels/processed_string" action="/processed_string/{input_string}"> 
     <input id="input_string" name="input_string" /> 
    </form> 
</body> 

这给我们带来的 “论据” 资源的实例。请注意,这不是一个JSON或XML文档,它只返回键/值对的普通数据;它是超媒体。它包含控件,引导用户接下来可以做的事情(有时指的是允许用户“跟随他们的鼻子”)。这个特定的URL(“/ arguments”)表示键/值对的空列表。如果我愿意的话,我可以命名为“/ empty_arguments”:这是一个例子,为什么从URL的角度考虑REST是愚蠢的:它实际上并不重要。

在这个新的HTML,为用户提供了他们可以浏览到三种不同的资源:

  1. 他们可以使用到“自我”导航到他们目前在相同的资源。
  2. 他们可以使用第一种形式导航到一个新资源,该资源表示一个参数列表,并使用它们在表单中指定的其他名称/值组对。
  3. 他们可以使用第二种形式提供他们希望最终替换的字符串。

注意:您可能会注意到,第二种形式有一个奇怪的 “行动” 网址:

/arguments?{key}={value}

在这里,我被骗了:我使用URI Templates。这使我可以指定参数将如何放置到URL上,而不是使用仅使用<input-name>=<input-value>的默认HTML方案。很显然,为了这个工作,用户不能使用浏览器(因为浏览器没有实现这个功能):他们需要使用理解HTML模板的软件。当然,我使用HTML作为示例,您的REST服务可以使用某种支持URI模板规范定义的URI模板的XML。

无论如何,假设用户想要添加他们的参数。用户使用第一种形式(例如,用“作者”填写“键”输入,用“John Doe”填写“价值”输入)。这导致...

GET /参数?作者约翰=%20Doe

<body> 
    <a rel="self" href="/arguments?Author=John%20Doe"/> 
    <form rel="http://example.com/rels/arguments" method="get" action="/arguments?Author=John%20Doe&{key}={value}"> 
     <input id="key" name="key" type="text"/> 
     <input id="value" name="value" type="text"/> 
    </form> 
    <form rel="http://example.com/rels/processed_string" action="/processed_string/{input_string}?Author=John%20Doe"> 
     <input id="input_string" name="input_string" /> 
    </form> 
</body> 

现在这是一个全新的资源。您可以使用单个键/值对将它描述为参数列表(键/值对):“作者”/“John Doe”。 HTML与以前几乎相同,只是有一些变化:

  1. “自我”链接现在指向当前资源URL(从“/ arguments”更改为“/ arguments?Author = John%20Doe”
  2. 第一种形式的“动作”属性现在有较长的网址,但我们再次使用URI模板,使我们能够建立一个更大的URI。
  3. 第二种形式

用户现在希望要添加一个“Date”参数,所以他们再次提交第一个表单,这次用“Date”键和一个值“2003-01-02” 。

GET /参数?作者约翰=%20Doe &日期= 2003-01-02

<body> 
    <a rel="self" href="/arguments?Author=John%20Doe&Date=2003-01-02"/> 
    <form rel="http://example.com/rels/arguments" method="get" action="/arguments?Author=John%20Doe&Date=2003-01-02&{key}={value}"> 
     <input id="key" name="key" type="text"/> 
     <input id="value" name="value" type="text"/> 
    </form> 
    <form rel="http://example.com/rels/processed_string" action="/processed_string/{input_string}?Author=John%20Doe"> 
     <input id="input_string" name="input_string" /> 
    </form> 
</body> 

最后,用户准备处理他们的字符串,所以他们使用的第二种形式,并填写“ input_string“变量。这又一次使用URI模板,从而将用户带到下一个资源。比方说,该字符串如下:

{Author} wrote some books in {Date}

的结果将是:

GET/processed_string /%7BAuthor%7D +写+有些+书籍+在+%7BDate%7D作者? = John%20Doe & Date = 2003-01-02

<body> 
    <a rel="self" href="/processed_string/%7BAuthor%7D+wrote+some+books+in+%7BDate%7D?Author=John%20Doe&Date=2003-01-02"> 
    <span class="results">John Doe wrote some books in 2003-01-02</span> 
</body> 

PHEW!这是很多工作!但它是(AFAIC)RESTful,并且它满足了不需要在服务器端实际存储ANYTHING(包括参数列表或最终想要处理的字符串)的要求。

重要的事情要注意

有一点是这里重要的是,我不只是在谈论的URL。实际上,大部分时间我都在谈论HTML。 HTML是超媒体,这是REST中被遗忘的很大一部分。所有那些声称他们是“宁静的”,他们说“在这个URL上使用这些参数进行GET并在这个URL上使用类似这样的文档进行POST”的API并没有实践REST。罗伊菲尔丁(字面上wrote the book on RESTmade this observation himself

另一件需要注意的事情是,设置参数有点痛苦。在初始GET /到达服务的根目录(你可以认为它是“菜单”)之后,你需要再做5个GET调用才能建立你的参数资源来创建四个关键字的参数资源/值配对。这可以通过不使用HTML来缓解。例如,我已经在我的例子中使用了URI模板,没有理由说HTML对REST来说不够好。使用支持类似于表单的超媒体格式(如XML的一些派生),但能够指定值的“映射”,您可以一次完成此操作。例如,我们可以使用我们的API能够理解的“映射”输入类型是什么,所以长扩展HTML媒体类型,以允许其他所谓的“映射”输入型...

的客户,他们会能够通过一个GET构建他们的参数资源。

在这一点上,你可能甚至不需要“参数”资源。你可以只直接跳到包含映射和实际字符串“processed_string”资源...

什么文件上传?

好吧,所以最初你提到文件上传,以及如何得到这个,而不需要存储文件。那么,基本上,我们可以使用我们现有的示例,但用文件替换最后一步。

在这里,我们基本上做同样的事情和以前一样,除了我们正在上传文件。需要注意的是,现在我们暗示用户(通过表单上的“method”属性)他们应该执行POST而不是GET。请注意,尽管处处听到POST是非安全的(它可能导致服务器发生更改),但是非幂等操作,没有任何说它必须是服务器上的更改状态。

最后,服务器可以返回新文件(甚至更好的办法是返回一些超媒体或LOCATION标头,并带有到新文件的链接,但这需要存储)。

最终评论

这只是一个拿这个具体的例子。虽然我希望你已经获得某种见解,但我会提醒你接受这个福音。我敢肯定,我曾经说过一些事情并不是真正的“休息”。我计划发布这个问题并回答REST-Discuss Mailing List,看看别人对此有何评论。

我希望通过这个来表达一件主要的事情,那就是最简单的解决方案可能就是使用RPC。毕竟,你最初尝试使RESTful试图完成什么?如果你试图告诉人们你完成了“REST”,请记住,大量的API声称自己是“RESTful”,它们真的只是RPC被名词而不是动词所伪装的URL所伪装。

如果是因为您已经听说了REST的一些好处,以及如何通过使您的API RESTful隐含地获得这些好处,那么不幸的事实是,除了URL以外,REST还有更多其他优点,以及您是否对其进行GET或POST 。超媒体扮演着重要角色。

最后,有时您会遇到问题,这意味着您可能会做SEEM非RESTful的事情。也许你需要做一个POST而不是一个GET,因为这个URI(它有一个理论上无限的存储量,但有很多技术限制)会变得太长。那么,你需要做POST。也许

更多资源:

相关问题