How can I create a RESTful calculator?
Asked Answered
F

5

34

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?

Few answered 25/11, 2011 at 23:54 Comment(1)
So what exactly is your question?Sherburne
P
21

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.

Peptone answered 26/11, 2011 at 0:27 Comment(3)
Thanks Brian! So if methods can also be modelled as (sub-)resources, can I also write "GET calc.com/arithmeticCalc/add?a=3&b=4" ?Few
Yes, but I'd avoid adding verbs to your URI structure. You already have verbs within HTTP, so you should just use nouns to describe your resources within your URIs. That way your API clients won't be confused about how to use each resource. Imagine you do an HTTP POST to an /add resource - how would I know if it would do an actual addition or create a sub-resource? To avoid the confusion in your example, I'd change it slightly to calc.com/arithmeticCalc/adder?a=3&b=4.Peptone
Query parameters are actually key-value pairs, so in Brian's answer, he actually creates key:null pairs, where the keys are 3, 4 and "+", all of them have empty values. Query params are also not specified by any ordering, therefore this interface is ambiguous. For example, server implementations aren't told to care about the ordering of the query params: 1&2&- could mean 2-1, or 1-2. Also, query parameters are not designed for processing like this, its for identifying a resource. RFC 3986Jessalin
P
43

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.

Partook answered 10/4, 2014 at 0:35 Comment(1)
This makes a lot of sense when the input to your calculator might be a large bit of JSON (for example several computations to be run).Steenbok
P
21

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.

Peptone answered 26/11, 2011 at 0:27 Comment(3)
Thanks Brian! So if methods can also be modelled as (sub-)resources, can I also write "GET calc.com/arithmeticCalc/add?a=3&b=4" ?Few
Yes, but I'd avoid adding verbs to your URI structure. You already have verbs within HTTP, so you should just use nouns to describe your resources within your URIs. That way your API clients won't be confused about how to use each resource. Imagine you do an HTTP POST to an /add resource - how would I know if it would do an actual addition or create a sub-resource? To avoid the confusion in your example, I'd change it slightly to calc.com/arithmeticCalc/adder?a=3&b=4.Peptone
Query parameters are actually key-value pairs, so in Brian's answer, he actually creates key:null pairs, where the keys are 3, 4 and "+", all of them have empty values. Query params are also not specified by any ordering, therefore this interface is ambiguous. For example, server implementations aren't told to care about the ordering of the query params: 1&2&- could mean 2-1, or 1-2. Also, query parameters are not designed for processing like this, its for identifying a resource. RFC 3986Jessalin
D
4

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 JAX-RS 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.

Decrepitate answered 13/10, 2014 at 4:24 Comment(0)
S
3

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 naïve. It implies that each operation be performed separately as a GET to an "adder" or "subtractor". Of course, one can have the resource be "calculate" but then we're using a verb. We can change it to "calculator" or "answer", which are nouns but we really haven't done anything useful.

Schwarz answered 18/7, 2013 at 22:34 Comment(0)
I
0

To me, the most RESTful way to create a calculator would be to POST to a calculation endpoint and then GET it's result. Something like:

POST /calculation

{
  "expression": {
    "operation": "+",
    "left_term": 3,
    "right_term": {
      "expression": {
        "operation": "^",
        "left_term": "4",
        "right_term": "2"
      }
    }
  }
}
...
{
  "result": 19,
  "calculation_id": 123
}
---
GET /calculations/123
...
{
  "result": 19,
  "calculation_id": 123
}

You'd have to document it stating that a payload must be an expression containing an operation, a left and right term, and that terms can only be an int, float, string (constant) or another expression. This forces the user to be explicit with their expressions (basically every expression is a parenthetical), order is defined by the key name rather than payload position, and if you wanted to store the result the resulting resources also make sense as RESTful endpoints; or perhaps you'd do something like /calculations/123/result

Ingredient answered 14/7 at 1:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.