3

I have a resource that accepts transaction details as a subresource.

GET  /resources/{resourceId}/                         # get resource
POST /resources/{resourceId}/                         # create resource
POST /resources/{resourceId}/resourceTransactions/    # post a resource transaction

Now when posting a transaction, the main resource may get changed due to the transaction. Normally, I would simply return the posted resource transaction, however I would like to optimize the experience for the consuming client.

Options

1. No change

After POSTing the transaction, the transaction is returned and the consumer of the API must GET the main resource to see the changes.

2. Return the Main Resource

After POSTing the transaction, the main resource is returned to the consumer

3. Return a Projection of the Transaction with Main Resource embedded in the projection

After POSTing the transaction, the transaction is returned, and within it is a projection of the main resource

I would like to have a discussion of other options, as well as the advantages and disadvantages of the options I presented when consuming this kind of API.

2 Answers 2

2

The way you stated the question and the 3 possible options, may lead us to think that there's only one possible choice. In that sense, we may assume too that the client is going to be tigthly bound (coupled) to the choosen option.

However, there's a 4th option. It's, basically, by allowing clients to discover the associated resources.

I would like to optimize the experience for the consuming client.

Be Hypermedia.

HATEOAS

For brevity I will omit the definition of HATEOAS and its principles.

First of all, after POSTing the new resource, we don't return any representantion. We just return a 201 HTTP status and we inform the location (URL) of the created resource through HTTP Headers.

Request:
HTTP/1.1 /resource/X/transactions
....

Response
HTTP/1.1 201 CREATED
Content-Length: xxxx
Content-Type: xxxx​/xxx
Location: http://hostname/resource/x/transactions

The client will handle the response and follow the link informed in the Location header with a GET request.

The representantion of the transactions can provide the link to the parent resource implementing Links.

{
    #Transaction collection
   "collection" : [ ...], 
   "links" : [
         { "rel":"self", "href":"http://hostname/resource/x/transactions"},
         { "rel":"resource", "href":"http://hostname/resource/x"}
     ]
}

The benefits relies on the client now have several choices. It just need to follow the links. We also reduce the coupling between client and the API responses because the client don't need to know how the URL is.

Implementing HATEOAS may imply a deep review of your current implentation. If that option is out of any discussion, you also can transfer the links through the HTTP headers. For instance, implementing your own header: x-links.

Implementing new headers is quite common in the world of REST APIs. The convention states that we have to use the prefix x-. Checkout this question for more details

Note: If there's a reverse proxy in front of the API, it's required some modifications in the web server configuration to allow this new headers to be redirected alongside with the request.

Trade-offs

Pros & cons depends on your requirements. There's not one size fits all solution. Nevertheless, we can foresee the trade-offs.

1. No change

This approach is constraining the way the client scales or changes. The reason is that we have to hardcode URIs in the client. By doing this, we also introduce constraints in the workflow. And, of course, coupling.

2. Return the Main Resource

From my point of view, this approach introduce confusion to the "conversation" between the client and the API.

If we are working with transactions we may expect to keep working with transactions instead of another sort of resource. But It's mainly opinion based argument.

From the client point of view It also implies a second call to the API for retriving the actual state of the transactions after the POST.

Two trips through the wire may seems a trivial thing till we are faced with the Fallacies of the distributed computing.

It also adds the constraints mentioned in the previous option.

3. Return a Projection of the Transaction with Main Resource embedded in the projection

It could be usefull if we have API calls restrictions. Cutting down calls to the API may help to relax the concurrency in the server side.

This approach is the closest to the one I suggested. The difference relies on the fact that HATEOAS implies more network trips.

The drawback, IMO, is that the resources representantions become a little bit verbose:

  • resources rep. + embedded rep. of the transactions

  • transactions rep. + embedded rep. of the parent resource.

Maybe, another drawback comes with implenting security. If there're data access constraints, it my introduce overhead in the server side. But it's pure speculation. Depends on the data access policies we have to implement. If any.

4. HATEOAS

As I have mentioned, It implies more trips through the network. More calls to the API may cause more work for the server (depends on you caching strategy).

It may add some difficulties if there's API management in front of the API. We have to assure that all the links returned are available through any possible Gateway/Proxy in-between.

On the other hand, the benefits are: flexebility in both sides (client and server), loosely coupling, easier integrations.

Finally ..

the right way to do it is the way that best suites your functional and non-functional requirements. Be flexible, the solution may come by adopting one or more of them. Or another option not introduced here.

0

There are two options that I would suggest. The first option is to POST/PATCH/PUT to the resource URI directly to create or update the resource:

POST/PATCH/PUT /resources/123/ HTTP/1.1

which returns the resource directly, with a link to the transaction resource:

HTTP/1.1 200 OK
Link: </resources/123/transaction/a089a6cc-e64f-40b9-a786-238f2a32cfbb>; rel=transaction

"representation of /resources/123"

Other link relation type you might want to use might be some sort of rel=permalink to indicate that the link is for a specific version of the resource.

The second option is to update indirectly by creating a transaction object:

PUT /resources/123/transaction/a089a6cc-e64f-40b9-a786-238f2a32cfbb HTTP/1.1

which should return a response with a Content-Location header and a representation of the updated resource in the response body:

HTTP/1.1 201 Created
Content-Location: /resources/123

"representation of /resources/123"

As per HTTP spec, the Content-Location (not to be confused with Location header that are normally used for redirects) tells the client that the response body is the resource pointed by the Content-Location header.

Content-Location:

The Content-Location entity-header field MAY be used to supply the resource Location for the entity enclosed in the message when that entity is accessible from a Location separate from the requested resource’s URI.

1
  • I like the Content-Location approach, I didn't think in it till you mentioned. I guess that my answer is still valid due to the location of the content is the same URI. The difference relies on the method. I would expect a basic redirection with GET if Location header is informed so that the client would not have to implement the redirection. It would be performed by the http client instead.
    – Laiv
    Apr 29, 2017 at 15:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.