Expressing side effects in responses


#1

When an action has side effects (non-relationship) how should these be reported in a response?

e.g.

I have a shopping cart that contains a collection of items.

Items can be products, promotions/discounts, shipping charges etc.

I have a 2 for 1 discount and 2 items that are applicable, if I remove one of those items how should I represent the removal of the discount item in the response?

Any tips/guidance gratefully received.


#2

I would deal with that within the client.

The UI should make it clear that those two items cost the price of one. If the user deletes one of the item, then the price is adjusted.


#3

thanks for the response maark…

Ui is not an option here unfortunately - this is an api so stripping it all back I suppose the question is what is the best way to handle a request that has side effects where relationships are not involved.

My initial thoughts were to return 207 (predicated on the primary purpose of the request being successful - otherwise we’d error and the side-effects would not be a consideration)) and then detail each side-effect in the meta-data of root of the response.

In the [poor] example I give in the OP - the promotion_item would be removed because one of the items it relates to has been removed and therefore the requirements of that promotion are no longer fulfilled.

I’m struggling to think of any other way that my initial idea that would satisfy this requirement.

I do hope others have some ideas too - this feels like something that would be useful and also benefit from the minds of teh jsonapi community to make it useable/sensible


#4

Not sure which example you are talking about, but this sounds like a good idea.

You have an order which contains items. You have a promotions relationship too. Whenever a promotion applies to your order, you add it to the list of promotions. When an item is removed, you can remove the promotions that are associated to this item from the promotions relationship.

Whoever is using the API can find a list of active promotions on any order and when they modify on order, they can compare the new order to see the promotions that were added or removed.


#5

I’m keen to here others thoughts on the 207 response code and then further details in the meta-data solution - is it a valid use of meta-data?

What other possible solutions could be applied?


#6

So, I realize I’m late to this party but starting from the top.

I would rethink your design if you believe a shopping cart is a collection of polymorphic items which have such substantially different semantics which would require an intelligent client to be reactive to the representation schema itself. One item is an item, another is a conditional price modifier, another is a fee, and your list continues and that will make the requirements of your client get ever more complex. The cart should be a container with relationships to many resources of the known qualities to prevent ambiguity and reliance on duplication of your specific business logic.

Your premise is a side effect of the ambiguity inherent in trying to rehydrate the semantic differences you casually discarded in the design of the cart in the first place. The solution in your example isn’t to come up with a clever means to solve the problem, but fix the design and then you won’t have the problem.

To further illustrate the point, this should apply the discount to the items (not removing anything), and it should be defined with preconditions (inputs) and the expected output (negative line item price). With that design there isn’t a side effect which is hidden by the operation, its all returned as part of the main representation and is traceable.

I see the example you set up is contrived, so it begs the question: is this always a case of sub optimal API design?

207 is an interesting thought, however {json:api} is rather prescriptive in it’s formats and I would suggest you write an extension specification on the WebDAV multi status element for application/json and then project it to application/vnd.api+json with an official {json:api} extension before you proceed on that path. The point of all this is to do things in a standards oriented way. {json:api} doesn’t address transactions or chaining (yet), because the semantics of HTTP are not RPC by nature, and collections of operations passed as a single interaction is bordering very closely on RPC.