Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

REST API for data processing and method chaining

I apologize in advance if the quality of the question is bad. I am still beginning to learn the concepts of REST API. I am trying to implement a scalable REST API for data processing. Here is what I could think of so far.

Consider some numerical data that can be retrieved using a GET call:

GET http://my.api/data/123/

Users can apply a sequence of arithmetic operations such as add and multiply. A non-RESTful way to do that is:

GET http://my.api/data/123?add=10&multiply=5

Assupmtions:

  • The original data in the DB is not changed. Only an altered version of it is returned to the user.
  • The data is large in size (say a large multi-dimensional array), so we can't afford to return the whole data with every opertation call. Instead, we want to apply operations as a batch and return the final modified data in the end.

There are 2 RESTful ways I am currently conisdering:

1. Model arithmetic operations as subresources of data.

If we consider add and multiply as subresources of data as here. In this case, we can use:

GET http://my.api/data/123/add/10/

which would be safe and idempotent, given that the original data is never changed. However, we need to chain multiple operations. Can we do that?

GET http://my.api/data/123/add/10/multiply/5/

Where multiply is creating a subresource of add/10/ which itself is a subresource of data/123

Pros:

  • Statelessness: The sever doesn't keep any information about the modified data.
  • Easy access to modified data: It is just a simple GET call.

Cons:

  • Chaining: I don't know if it can be easily implemented.
  • Long URIs: with each operation applied, the URI gets longer and longer.

2. Create an editable data object:

In this case, a user creates an editable version of the original data:

POST http://my.api/data/123/

will return

201 Created
Location: http://my.api/data/123/edit/{uniqueid}

Users can then PATCH this editable data

PATCH http://my.api/data/123/edit/{uniqueid}
{add:10, multiply:5}

And finally, GET the edited data

GET http://my.api/data/123/edit/{uniqueid}

Pros:

  • Clean URIs.

Cons:

  • The server has to save the state of edited data.
  • Editing is no long idempotent.
  • Getting edited data requires users to make at least 3 calls.

Is there a cleaner, more semantic way to implement data processing RESTfully?

Edit:

If you are wondering what is the real world problem behind this, I am dealing with digital signal processing.

As a simple example, you can think of applying visual filters to images. Following this example, a RESTful web service can do:

GET http://my.api/image/123/blur/5px/rotate/90deg/?size=small&format=png
like image 406
ahmohamed Avatar asked Oct 14 '15 04:10

ahmohamed


2 Answers

There are multiple ways this can be done. In the end it should be clean, regardless of what label you want to give it (REST non-REST). REST is not a protocol with an RFC, so don't worry too much about whteher you pass information as URL paths or URL params. The underlying webservice should be able to get you the data regarless of how it is passed. For example Java Jersey will give you your params no matter if they are param or URL path, its just an annotation difference.

Going back to your specific problem I think that the resource in this REST type call is not so much the data that is being used to do the numerical operations on but the actual response. In that case, a POST where the data ID and the operations are fields might suffice.

POST http://my.api/operations/

{
    "dataId": "123",
    "operations": [
        {
            "type": "add",
            "value": 10
        },
        {
            "type": "multiply",
            "value": 5
        }
    ]
}

The response would have to point to the location of where the result can be retrieved, as you have pointed out. The result, referenced by the location (and ID) in the response, is essentially an immutable object. So that is in fact the resource being created by the POST, not the data used to calculate that result. Its just a different way of viewing it.

EDIT: In response to your comment about not wanting to store the outcome of the operations, then you can use a callback to transmit the results of the operation to the caller. You can easily add the a field in the JSON input for the host or URL of the callback. If the callback URL is present, then you can POST to that URL with the results of the operation.

{
    "dataId": "123",
    "operations": [
        {
            "type": "add",
            "value": 10
        },
        {
            "type": "multiply",
            "value": 5
        }
    ],
    "callBack": "<HOST or URL>"
}
like image 160
Jose Martinez Avatar answered Sep 28 '22 10:09

Jose Martinez


A couple of things worth reviewing in your question.

REST based API’s are resource based

So looking at your first example, trying to chain transformation properties into the URL path following a resource identifier..

GET http://my.api/data/123/add/10/multiply/5/

..does not fit well (as well as being complicated to implement dynamically, as you already guessed)

Statelessness

The idea of statelessness in REST is built around a single HTTP call containing enough information to process the request and provide a result without going back to the client for more information. Storing the result of an HTTP call on the server is not state, it’s cache.


Now, given that a REST based API is probably not the best fit for your usage, if you do still want to use it here are your options:

1. Use the Querystring with a common URL operation

You could use the Querystring but simplify the resource path to accept all transformations upon a single URI. Given your examples and reluctance to store transformed results this is probably your best option.

GET http://my.api/data/123/transform?add=10&multiply=5

2. Use POST non-RESTfully

You could use POST requests, and leverage the HTTP body to send in the transformation parameters. This will ensure that you don’t ever run out of space on the query string if you ever decide to do a lot of processing and it will also keep your communication tidier. This isn’t considered RESTful if the POST returns the image data.

3. Use POST RESTfully

Finally, if you decide that you do want to cache things, your POST can in fact store the transformed object (note that REST doesn’t dictate how this is stored, in memory or DB etc.) which can be re-fetched by Id using a GET.

Option A

POSTing to the URI creates a subordinate resource.

POST http://my.api/data/123
{add:10, multiply:5}

returns

201 Created
Location: http://my.api/data/123/edit/{uniqueid}

then GET the edited data

GET http://my.api/data/123/edit/{uniqueid}

Option B

Remove the resource identifier from the URL to make it clear that you're creating a new item, not changing the existing one. The resulting URL is also at the same level as the original one since it's assumed it's the same type of result.

POST http://my.api/data
{original: 123, add:10, multiply:5}

returns

201 Created
Location: http://my.api/data/{uniqueid}

then GET the edited data

GET http://my.api/data/{uniqueid}
like image 33
Oliver Gray Avatar answered Sep 28 '22 10:09

Oliver Gray