I'm designing an API Service that returns only JSON representations.
Some background and context to my question... Behind the scenes a product in my database has an associated set of prices. Prices consist of (qty
, currency_code
, unit_price
) tuples. Each set of prices belong to a particular product and price list.
Here's a glance at the relational database data. Each row has a unique constraint on (product_id
, price_list_id
, currency_code
, qty
). Both product_id
and price_list_id
are forreign keys.
dev=# SELECT * FROM
price
WHERE
product_id = 1 AND price_list_id = 1 AND currency_code = 'GBP';
id | uuid | product_id | price_list_id | qty | currency_code | unit_price | created | modified
----+--------------------------------------+------------+---------------+-----+---------------+------------+----------------------------+----------------------------
1 | 6fcbbb5b-8e51-4a4c-bf63-270f5d3f1ff8 | 1 | 1 | 1 | GBP | 20417 | 2019-08-15 15:49:19.508808 | 2019-08-15 15:49:19.508808
16 | c044e9fe-bb5f-4996-b8e6-88b4a1b9f125 | 1 | 1 | 2 | GBP | 3453345 | 2019-08-15 15:49:37.896681 | 2019-08-15 15:49:37.896681
17 | c488d372-e58f-4441-a583-281e4c2b1310 | 1 | 1 | 3 | GBP | 312353345 | 2019-08-15 15:49:41.320622 | 2019-08-15 15:49:41.320622
To retrieve a set of prices for a given product I intend to use a GET
request to the /products/:product_id/prices?price_list_id=1¤cy_code=GBP
resource. I expect to receive:
[
{ id: "6fcbbb5b-8e51-4a4c-bf63-270f5d3f1ff8", "qty": 1, "unit_price": 20417 },
... etc // 3 items total
]
If I want to update a set of prices for a given (product_id
, price list_id
and currency_code
), is it acceptable to do the exact reverse by doing a PUT
request to the same URI that I used for the GET
, i.e., PUT /products/:product_id/prices/price_list_id=1¤cy_code=GBP
or should I use an alternative?
In the context of a GET
request having price_list_id=1
and currency_code=GBP
act like filters. Whilst using a PUT
request I'm not sure if it's okay to identify a resource for updates using a query parameter as a filter.
Alternatives I've considered are:
PUT /products/:product_id/prices
and place theprice_list_id
andcurrency_code
in the request body. e.g.
{
"price_list_id": "<uuid>",
"currency_code": "GBP",
"data": [
{ "qty": 1, "unit_price": <newprice> },
... /* new set of prices */
]
}
thereby deleting all existing prices and replacing the set with those in the request body.
PUT /products/:product_id/prices/price-lists/:price_list_id
which starts to look very long winded.products
have manyprices
so the first part of the resource looks okay to nest as a subresource. However,prices
don't haveprice-lists
(it's the opposite way around) so it makes no sense to haveprice-lists
as a sub resource of prices.PUT /prices/:price_id
. This means I have to first retrieve a list, delete them one by one and update prices individually. This is not a good solution as I want to operate on prices as a set collectively. I also want the set to be replaced as a whole or none at all.