Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RESTful API Design: PUT or POST for creating many-to-many relationships?

Tags:

rest

http

api

For designing and creating a RESTful API the following question occurs:

The API supports GET (for queries), POST (for creating), PUT (for updates) and DELETE (for deleting).

Lets assume in the database we have an article and a shop both already existing.

Now we need a rest call to link the article instance to the shop instance. Which of the following solutions is the best / most clean REST design:

  1. /shop/id/article/id/ --> with POST
  2. /shop/id/article/id/ --> with PUT
  3. /shoparticlerelation/ --> with POST (object with ids in body)
  4. /shoparticlerelation/ --> with PUT (object with ids in body)

If there is no clear answer or all solutions are equally good this may also be a valid answer if there is a clear argumentation why.

like image 282
Blackbam Avatar asked Mar 15 '23 15:03

Blackbam


2 Answers

I presume in this situation you already have a collection of shops and a collection of articles, and you just wish to link two together.

One option is to expose a more db like 'resource' that presents this link, and have operations like

POST /shopArticleLinks HTTP/1.1

{ "shop"  : xxx,
  "article: YYY
}

I would personally look to expose it as a property of the shops and/or articles in a more natural manor, like

PUT /shop/<ID> HTTP/1.1

{ /* existing details */
  "articles": [ /* list of articles */ ]
}

I've used JSON there, but of course use what ever format you want to use. I've also stuck with using PUT as you stated, but keep in mind that with PUT you should send a full replacement for the new modified version, PATCH can be used to send partial updates, but then you need to consider how you want do that, may something like

PATCH /shops/<ID>/articleLinks HTTP/1.1

{ "add"   : [],
  "remove : []
}

Don't forget that server side you can look at what articles are being refereed to and ensure they have a proper back pointer.


Additional thoughts

Regarding the second method, where you expose the link as a property of the shop and/or article resources. Keep in mind that it is perfectly acceptable (and in this case rather appropriate) that when you update the links in a given shop that the links in the corresponding articles are also updated.

like image 142
thecoshman Avatar answered Apr 27 '23 02:04

thecoshman


/shop/id/article/id/

You cannot use this because at the moment you want to link them, this endpoint doesn't (or at least shouldn't) yet exist. It is the action of linking them together that should define this endpoint.

/shoparticlerelation/

You should not use this because a shoparticlerelation is not a resource / entity. Usually with rest, every named url segment represents a resource that can be CRUD-ed. /shops is a good example and so is /articles but this one isn't.


I suggest the following:

Define the following endpoints

/shops for POSTing new shops
/shops/id for operating on a single shop
/articles for POSTing new articles
/articles/id for operating on a single article

Then to link them together you can do a so called PATCH request, to update a shop's articles, or an article's shops:

PATCH /shops/1 HTTP/1.1

{
    "attribute": "articles",
    "operation": "add",
    "value": "8" // the article id
}

and

PATCH /articles/9 HTTP/1.1

{
    "attribute": "shops",
    "operation": "add",
    "value": "1" // the shop id
}

Based on your comments I made the assumption that an Article model has a list of Shops as attribute, and vice-versa, making this approach valid.

A PATCH request is used to modify an existing resource by specifying how and what to update. This is different from a PUT because a PUT replaces the entire resource with values from the request, however PATCH is only used to modify (not replace) a resource.

like image 33
Tim Avatar answered Apr 27 '23 03:04

Tim