【问题标题】:How can I create a RESTful calculator?如何创建 RESTful 计算器?
【发布时间】:2011-11-25 23:54:53
【问题描述】:

鉴于 RESTful Web 服务都基于“一切都表示为资源并且可以通过地址 (URI) 访问”这一神圣理念,这对于 CRUD 应用程序可能是有意义的(所有示例都是关于列表/创建/更新/删除实体)。但是,其他业务逻辑如何,例如创建一个与 CRUD 操作无关的简单计算器 RESTful 服务? 这样的 REST 服务有什么好的设计?

其次,如果 SOAP 的逻辑已经完全合理,那么使用 REST 而不是 SOAP 的真正优势是什么?

【问题讨论】:

  • 那么你的问题到底是什么?

标签: web-services rest


【解决方案1】:

HTTP POST 不一定要创建持久资源。在RFC 2616, section 9.5 我们发现:

POST 方法执行的操作可能不会产生资源 可以通过 URI 标识。在这种情况下,200(OK)或 204 (No Content) 是适当的响应状态,取决于是否 响应中是否包含描述结果的实体。

这意味着我们可以考虑“创建一个计算”,而不必将该计算的结果保存在它自己的 URL 中。您的 API 可能如下所示:

Request:
POST /calculations
Content-Type: text/plain

3 + 3 / 12 ^ ( 3 * PI)

Response:
200 OK
Content-Type: text/plain

3.005454

这样做的好处是您不会通过 URL 传递“内容”,当您尝试通过 URL 长度有限的客户端或代理提交长计算时,这会中断。您还可以支持请求和响应的不同表示。

【讨论】:

  • 当计算器的输入可能是大量 JSON(例如要运行多个计算)时,这很有意义。
【解决方案2】:

计算器服务很容易以 RESTful 方式建模。 “CRUD”中的“R”代表“读取”,没有理由“读取”不能也意味着“计算”。所以可以通过 GET 访问一个简单的Reverse Polish 计算器服务:

GET https://calc.com/rpnCalc?3&4&%2B
7

上面的 URI 方案只是在 GET 请求中添加了三个参数:

3
4
+ (URL-encoded as %2B)

这是一个幂等、安全且可缓存的请求。如果这是一个非常复杂的数学查询,需要花费几分钟的时间来计算,我可以将这些查询路由到一个开箱即用的 HTTP 代理,并在重复查询相同的 URI 时使用它立即返回任何预先计算的值。

根据您需要执行的计算类型,您还可以将非常复杂的查询发布到计算器资源(将查询作为请求正文传递),服务器可能会将 URI 返回到“结果”资源,然后你可以 GET 来检索结果,甚至对它们进行分页。

其次,使用 REST 而不是 SOAP 的真正优势是什么? SOAP 的逻辑已经完全说得通了?

我可以使用curl 之类的命令行工具访问上述计算器服务,而无需构建复杂的 SOAP。我可以在几秒钟内对它的调用进行编码,而无需使用任何第三方 XML 库或 SOAP 工具包。我可以使用 HTTP 代理等商品工具来缓存结果并提高性能。我不必担心 SOAP 互操作性或检查 WS-I 兼容性。如果我正确使用超链接,那么我可以在不影响现有客户或让他们重新编译的情况下改进和改进我的服务。没有要版本的 WSDL,也没有我必须维持多年的脆弱合同。客户已经知道 GET/PUT/POST/DELETE 做什么,我不必重新定义或重新记录它们的语义。决定他们更喜欢 JSON 而不是 XML 的 API 客户端可以使用 HTTP 的内置内容协商功能来获取它。使用 SOAP 和 Web 服务,我绝对可以做到这些事情。

嘿,如果 SOAP 符合您的需求,那就试试吧。使用 REST 有很多好处,但它们可能不适合您的情况。至少,通过一本像样的书like this one 了解 REST 能给您带来什么,然后在了解完整故事后下定决心。

【讨论】:

  • 谢谢布赖恩!所以如果方法也可以建模为(子)资源,我也可以写“GET calc.com/arithmeticCalc/add?a=3&b=4”吗?
  • 是的,但我会避免在你的 URI 结构中添加动词。 HTTP 中已经有动词,因此应该只使用名词来描述 URI 中的资源。这样您的 API 客户端就不会对如何使用每个资源感到困惑。想象一下,您对 /add 资源执行 HTTP POST - 我怎么知道它是否会执行实际添加或创建子资源?为了避免您的示例中的混淆,我将其稍微更改为calc.com/arithmeticCalc/adder?a=3&b=4
  • 查询参数实际上是键值对,所以在Brian的回答中,他实际上创建了key:null对,其中键是3、4和“+”,它们都有空值。查询参数也没有按任何顺序指定,因此这个接口是不明确的。例如,不告诉服务器实现关心查询参数的顺序:1&2&- 可能意味着 2-11-2。此外,查询参数不是为这样的处理而设计的,它用于识别资源RFC 3986
【解决方案3】:

这是 REST 中名词和动词之间紧张关系的一个很好的例子。使用“add”或“adder”作为资源的建议非常幼稚。这意味着每个操作都作为对“加法器”或“减法器”的 GET 单独执行。当然,可以让资源为“计算”,但我们使用的是动词。我们可以把它改成“计算器”或“答案”,它们是名词,但我们真的没有做任何有用的事情。

【讨论】:

    【解决方案4】:

    这个问题已经有几年了。但似乎仍然是一个让我和很多同事感到困惑的问题。我们未能找到让所有人都满意的解决方案。

    但是对于一个简单的计算器,我认为下面的 JAX-RS 实现提供了一个干净的 API。

    /**
     * This class defines a CalculatorResource.
     */
    
    @Path("v{version}/calculators/{id}")
    @Named
    public class CalculatorResource {
        
        private final Long value;
        
        public CalculatorResource() {
            value = 0L;
        }
        
        public CalculatorResource(Long initialValue) {
            this.value = initialValue;
        }
    
        @GET
        public Long getValue() {
            return value;
        }
    
        @Path("+{value}")
        public CalculatorResource add(@PathParam("value") Long value) {
            return new CalculatorResource(this.value + value);
        }
        
        @Path("-{value}")
        public CalculatorResource subtract(@PathParam("value") Long value) {
            return new CalculatorResource(this.value - value);
        }
        
        @Path("*{value}")
        public CalculatorResource multiply(@PathParam("value") Long value) {
            return new CalculatorResource(this.value * value);
        }
    
    }
    

    通过这样的实现,URI 可以是一个易于阅读的公式。

    例如。 /api/v1/calculators/mycalc/+9/-4/*3/+10 将返回 25

    【讨论】:

      猜你喜欢
      • 2013-09-18
      • 2014-07-04
      • 2014-06-24
      • 1970-01-01
      • 2012-12-30
      • 2012-02-19
      • 1970-01-01
      • 2015-04-07
      • 1970-01-01
      相关资源
      最近更新 更多