I'm looking at a scenario where we have one parent resource (real name removed to protect the innocent). As a child object, we have a list of prices organized by effectiveDate.
Preexisting CRUD on api/resource
New POST on api/resource/{code}/someRelationship/{relId}/prices
A few months ago we created the POST prices endpoint. It takes a list of price objects. Currently this appends new prices to a pre-existing list in the database. There's no handling of duplicates when we consume these prices other than the last in wins if the effectiveDates are the same. We did not expose an id and just wanted to associate some prices to the parent resource object given someRelationship.
{
"prices": [
{
"price": 0,
"effectiveDateTime": "2020-02-14T18:30:33.710Z"
}
]
}
Life went on. Things got more complicated. We ran into a situation where something might change in the source of truth system where the effectiveDate shifts. If this happens, we believe that we will incorrectly leave behind remnant prices on the system that we're synchronizing to. The new ones will get pushed over, but there will be old prices that are no longer correct. It seems drastically easier to just take whatever the system we're synchronizing from gives us because it's the source of truth for prices.
Options:
- Lean into
POST api/resource/{code}/someRelationship/{relId}/prices- Can we continue to treat the
pricesobject as a list belonging to the parentresourcerather than a first class, restful object? - Change the POST logic to wipe out the old
prices, and save the new ones that were broadcast by the calling system since it knows about ALL thepricesand can save them in one call. - We can argue if it should be named PUT or POST. Sounds like POST to me.
- I'm told this breaks all that is holy with restful conventions.
- Would have to update api docs to communicate this functionality because we broke the restful conventions.
- Can we continue to treat the
- promote the
pricesobject to a first class, restful object of the api.- But this means we'll have to create full CRUD endpoints exposing the id
- or use the effectiveDateTime as the id which seems weird
- Workflow for the caller to juggle full CRUD of
pricesGET /api/resource/{code}/someRelationship/{relId}/prices- to get a list to know what changes to push over
pricein both sides with the same value and effectiveDate? Do nothing.POST /api/resource/{code}/someRelationship/{relId}/pricespricemissing from side to be synchronized? POST it one by one? Or can we add it to a list and POST the list? what if we have 100 prices? 100 APIs calls?
PUT /api/resource/{code}/someRelationship/{relId}/prices/{id}pricewrong from side to be synchronized? PUT it one by one.
DELETE /api/resource/{code}/someRelationship/{relId}/prices/{id}pricein the side to be synchronized but missing in the source of truth? Delete it one by one.
- comparison logic could get more confusing if we continue to add fields to what a
priceis (more than price and effectiveDate) - Example: Multiply by 12 months times a few parent
resources. 12 months * 100priceAPI calls * 5resources= 6000 calls?
- But this means we'll have to create full CRUD endpoints exposing the id