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
, ie, 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 the price_list_id
and currency_code
in the request body. eg {
"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 many prices
so the first part of the resource looks okay to nest as a subresource. However, prices
don't have price-lists
(it's the opposite way around) so it makes no sense to have price-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.
The url you are sending a PUT request to should be the 'identity' of the thing you are updating. Including information to locate the resource inside the request body does therefore not make sense.
All the information the server needs to 'locate' the resource you are updating should be in the resource locator (that's the url!)
All of these are completely fine from a HTTP protocol perspective:
PUT /products/:product_id/prices?price_list_id=1¤cy_code=GBP
PUT /products/:product_id/prices/price-lists/:price_list_id
PUT /prices/:price_id
It doesn't really matter if your ids are in the path part of query part of the url, it should be irrelevant. For purposes of locating resources there's no difference between /article/5
and /article?id=5
.
So which one you choose should be based on consistency within your own API, user-friendliness, etc.
It's interesting that you don't like option 2 for being too long-winded, but you're ok with option 1 which is even longer though ;)
You can use PATCH /products/:product_id/prices
See this answer to a similar question:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.