通过HTTP模拟过程调用的最佳/最RESTful方法是什么?

时间:2012-03-15 20:10:18

标签: rest get

我有一个服务,它接受.odt模板文件和一些文本值,并在输出时生成.odt。我需要通过HTTP提供此服务,我不太清楚什么是使REST接口工作的最RESTful方式。

我需要能够将模板文件和输入值提供给服务器 - 并将生成的.odt文件发送给我。我看到的关于它如何工作的选项是:

  1. 将模板PUT或POST到服务器,然后执行GET请求,传递我刚发布的模板的URI,加上输入值 - GET响应正文将有.odt
  2. 在单个GET请求中发送模板和参数 - 模板文件将放在GET请求正文中。
  3. 和上面的(2)一样,除了将整个事件作为单个POST请求而不是GET。
  4. (1)的问题是我不想将模板文件存储在服务器上。这增加了复杂性并且存储文件对我来说没有用,除了它是一个非常RESTful的方法。此外,单个请求优于2,所有其他条件相同。

    (2)的问题在于,将一个正文放入GET请求中就是滥用HTTP - 我现在使用的软件支持它,但可能并不总是如此。

    数字(3)似乎具有误导性,因为这更像是“阅读”或“获取”操作而不是“帖子”。

    我正在做的本质上就像一个函数调用 - 我需要在中传递大量的数据,我真的只是使用HTTP作为在网络上公开我的代码的便捷方式。也许我正在尝试做的本质上是非RESTful,并且没有REST友好的解决方案?任何人都可以建议吗?谢谢!

3 个答案:

答案 0 :(得分:6)

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

在过去一年左右的时间里,我试图通过书籍,邮件列表等方式更好地了解REST。出于某种原因,我决定选择你的问题来测试我所拥有的内容。得知。

抱歉:P


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

这是一种RESTful方式,它不需要存储在服务器上的任何东西。我将使用一些HTML(虽然已经破坏了,我会遗漏像HEAD这样的东西)作为我的媒体类型,只是因为它是众所周知的。

样本解决方案

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

GET /

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

这基本上为用户提供了一种开始实际与我们的服务交互的方法。现在他们只有一个选项:使用链接构建一组新的参数(最终将在字符串替换方案中使用的名称/值对)。所以用户转到该链接。

GET / arguments

<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>

这将我们带到一个&#34;参数的实例&#34;资源。请注意,这不是一个JSON或XML文档,只返回键/值对的明确数据;它是超媒体。它包含指导用户接下来可以做什么的控件(有时称为允许用户跟随他们的鼻子&#34;)。此特定URL(&#34; / arguments&#34;)表示键/值对的空列表。我很可能已经命名了url&#34; / empty_arguments&#34;如果我想:这是一个例子,为什么在URL方面考虑REST是愚蠢的:它真的不应该是什么URL。

在这个新的HTML中,用户可以获得三种不同的资源,可以导航到:

  1. 他们可以使用链接到&#34; self&#34;导航到他们当前所在的相同资源。
  2. 他们可以使用第一个表单导航到一个新资源,该资源表示一个参数列表,其中包含他们在表单中指定的附加名称/值配对。
  3. 他们可以使用第二种形式提供他们希望最终替换的字符串。
  4. 注意:您可能已经注意到第二种形式有一个奇怪的&#34;动作&#34;网址:

    /arguments?{key}={value}

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

    无论如何,让我们说用户想要添加他们的参数。用户使用第一个表单(例如,填写&#34;键&#34;输入&#34;作者&#34;&#34;值&#34;输入&#34; John Doe&#34; )。这导致......

    GET / arguments?作者= John%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>
    

    现在这是一种全新的资源。您可以将其描述为具有单个键/值对的参数列表(键/值对):&#34;作者&#34; /&#34; John Doe&#34;。 HTML与以前几乎完全相同,但有一些变化:

    1. &#34; self&#34;链接现在指向当前资源URL(从&#34; / arguments&#34;更改为&#34; / arguments?作者= John%20Doe&#34;
    2. &#34;行动&#34;现在,第一个表单的属性具有更长的URL,但我们再一次使用URI模板来构建更大的URI。
    3. 第二种形式
    4. 用户现在想要添加&#34;日期&#34;争论,所以他们再次提交第一个表格,这次是关键的&#34;日期&#34;和值#34; 2003-01-02&#34;。

      GET / arguments?作者= John%20Doe&amp; Date = 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>
      

      最后,用户已准备好处理他们的字符串,因此他们使用第二种形式并填写&#34; input_string&#34;变量。这再次使用URI模板,从而将用户带到下一个资源。让我们说该字符串如下:

      {Author} wrote some books in {Date}

      结果将是:

      GET / processed_string /%7BAuthor%7D +写了+一些+书+ +%7BDate%7D?作者= John%20Doe&amp; 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>
      

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

      需要注意的重要事项

      这里重要的一件事是我不是在谈论网址。事实上,大多数时候,我都在谈论HTML。 HTML是超媒体,它是被遗忘的REST的重要组成部分。所有那些说它们都是“宁静”的API。他们说&#34;使用这些参数对此URL进行GET,并在此URL上使用与此类似的文档POST#34;不练习REST。 Roy Fielding(字面意思wrote the book on RESTmade this observation himself

      另一件需要注意的事情是,设置参数是非常痛苦的。在初始GET /到达根目录(您可以将其视为&#34;菜单&#34;)之后,您需要再进行五次GET调用以构建您的参数资源以进行四个键/值对的参数资源。这可以通过不使用HTML来缓解。例如,我在我的示例中已经使用了URI模板,没有理由说HTML对于REST来说还不够好。使用支持与表单类似的超媒体格式(如某些XML派生),但能够指定&#34;映射&#34;价值观,你可以一气呵成。例如,我们可以扩展HTML媒体类型以允许另一种名为&#34; mappings&#34; ...

      的输入类型     

      只要使用我们的API的客户了解什么是&#34;映射&#34;输入类型是,他们将能够用一个GET构建他们的参数资源。

      那时,你可能甚至不需要一个&#34;参数&#34;资源。您可以直接跳到&#34; processed_string&#34;包含映射和实际字符串的资源...

               

      文件上传怎么办?

      好的,最初你提到了文件上传,以及如何在不需要存储文件的情况下获取文件。好吧,基本上,我们可以使用现有的示例,但用文件替换最后一步。

               

      在这里,除了我们上传文件外,我们基本上和以前一样。需要注意的是,现在我们向用户暗示(通过表单上的&#34;方法&#34;属性)他们应该进行POST而不是GET。请注意,即使在任何地方您都听到POST是不安全的(它可能导致服务器上的更改),非幂等操作,但没有任何说明它必须是服务器上的更改状态。

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

      最终评论

      这只是这个具体例子的一个例子。虽然我希望你获得某种洞察力,但我要提醒你接受这个作为福音。我确信有些事情我说的并不是真的&#34; REST&#34;。我打算发布这个问题并回答REST-Discuss Mailing List,看看其他人对此有什么看法。

      我希望通过这一点表达的一个主要问题是,最简单的解决方案可能只是使用RPC。毕竟,你最初尝试使RESTful试图完成的是什么?如果你试图告诉别人你已经完成了&#34; REST&#34;,请记住,有很多API声称自己已经声称自己已经声称自己已经声称自己已经完成了自己的工作。实际上只是用名词而不是动词来伪装成RPC的。

      如果是因为您已经听说过REST的一些好处,以及如何通过使您的API RESTful来隐含地获得这些好处,那么不幸的事实是,REST比URL更多,无论您是获取还是GET,张贴给他们。超媒体起着重要作用。

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

      更多资源:

答案 1 :(得分:1)

你正在做的事情不是REST-ful,或者至少在REST中难以表达,因为你首先考虑的是操作,而不是首先考虑的是对象。

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

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

但是,您可能会更好,只需实现RPC over HTTP模型,提交模板和值,然后同步获取响应 - 或者您命名的其他非REST模式之一......因为这只是你想要什么。

答案 2 :(得分:0)

如果存储模板没有值,那么选项2是最RESTful的,但是你知道有可能让你的GET主体掉线。

但是,如果我是这个系统的用户,每次我想用值填充它时,我都会发现上传模板非常浪费。相反,将模板存储起来并允许使用不同值的不同请求来填充生成的文档似乎更合适。