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
prices
object as a list belonging to the parentresource
rather 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 theprices
and 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
prices
object 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
prices
GET /api/resource/{code}/someRelationship/{relId}/prices
- to get a list to know what changes to push over
price
in both sides with the same value and effectiveDate? Do nothing.POST /api/resource/{code}/someRelationship/{relId}/prices
price
missing 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}
price
wrong from side to be synchronized? PUT it one by one.
DELETE /api/resource/{code}/someRelationship/{relId}/prices/{id}
price
in 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
price
is (more than price and effectiveDate) - Example: Multiply by 12 months times a few parent
resources
. 12 months * 100price
API calls * 5resources
= 6000 calls?
- But this means we'll have to create full CRUD endpoints exposing the id