How can I create a RESTful calculator?

2019-03-10 21:10发布

问题:

Given that RESTful web services are all based around the sacred idea that "everything is represented as resources and can be accessed by an address (URI)", this may make sense for CRUD applications (all examples are about listing/creating/updating/deleting entities). However, how about other business logic like, for example, creating a simple calculator RESTful service that has nothing to do with CRUD operations? What can be a good design for such a REST service?

Secondly, what is the real advantage of using REST over SOAP if the logic of SOAP already makes complete sense?

回答1:

A calculator service would be simple to model in a RESTful manner. The "R" in "CRUD" stands for "read", and there's no reason that "read" can't also mean "compute". So a simple Reverse Polish calculator service could be accessed via GET:

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

The URI scheme above simply adds three parameters to the GET request:

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

That's an idempotent, safe and cacheable request. If this was an insanely complicated math query that took many minutes to compute I could route these queries to an out-of-the-box HTTP proxy and use it to instantly return any pre-computed values should the same URI be queried repeatedly.

Depending on the kinds of calculations you need to do, you could also POST a very complex query to a Calculator resource (passing in the query as the request body) and the server might return the URI to a "result" resource, which you can then GET to retrieve the results, and even paginate through them.

Secondly, what is the real advantage of using REST over SOAP if the logic of SOAP already makes complete sense?

I can access the above calculator service using a command-line tool like curl without building a complex piece of SOAP. I can code calls to it in seconds without having to use any third-party XML library or SOAP toolkit. I can use commodity tools like HTTP proxies to cache results and improve performance. I don't have to worry about SOAP interoperability or check for WS-I compatibility. If I use hyperlinks correctly then I can evolve and improve my service without affecting existing clients or having them to even recompile. There's no WSDL to version and no brittle contract which I have to maintain for years. The clients already know what GET/PUT/POST/DELETE do and I don't have to redefine or re-document their semantics. API clients that decide they'd prefer JSON instead of XML can get it using HTTP's inbuilt content-negotiation feature. I can do absolutely zero of these things with SOAP and Web Services.

Hey, if SOAP fits your needs, have at it. There are many benefits to using REST but they might not be appropriate to your situation. At the very least, learn about what REST can give you with a decent book like this one and then make your mind up after getting the full story.



回答2:

An HTTP POST doesn't necessarily have to create a persisted resource. In RFC 2616, section 9.5 we find:

The action performed by the POST method might not result in a resource that can be identified by a URI. In this case, either 200 (OK) or 204 (No Content) is the appropriate response status, depending on whether or not the response includes an entity that describes the result.

This means we can think about "creating a calculation" without having to persist the result of that calculation at it's own URL. Your API could look like this:

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

3 + 3 / 12 ^ ( 3 * PI)

Response:
200 OK
Content-Type: text/plain

3.005454

This has the benefit that you're not passing "content" through the URL, which will break when you try to submit a long calculation through a client or proxy with limited length for URLs. You could also make support different representations for requests and responses.



回答3:

This question is couple of years old. But still seems to a question that confuses me and a lot of my colleagues. We have not been able to reach at a solution that satisfies everybody.

But for a simple calculator, I think the below JAXRS implementation provides a clean 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);
    }

}

With such an implemention, the URI can be an easy to read formula.

Eg. /api/v1/calculators/mycalc/+9/-4/*3/+10 would return 25.



回答4:

This is a good example of the tension between nouns and verbs in REST. The suggestion to use "add" or "adder" as the resource is tremendously naive. It implies that each operation be done as a GET to an "adder" or "subtractor". Of course one can have the resource be "calculate" but then we've using a verb. We can change it to "calculator" or "answer", which are nouns but we really haven't done anything useful.