Reputation: 9305
Lets say I have the following classes:
company
user
address
a company object can contain users and addresses, a user object contains addresses
company can exist on its own, but users and address is always a part of company or user (a composition in UML wording):
company ->
addresses
users ->
addresses
Now I want use the right REST-structure for POST (insert) and PUT (update) requests. What would be the correct approach?
variant 1:
// insert address:
POST /api/company/{companyId}/addresses
POST /api/company/{companyId}/users/{userId}/addresses
// update address:
PUT /api/company/{companyId}/addresses/{addressId}
PUT /api/company/{companyId}/users/{userId}/addresses/{addressId}
variant 2:
// insert address:
POST /api/address // companyId, userId etc. as parameter
// update address:
PUT /api/address/{addressId}
My personal gut feeling would be to use variant 1 for creation (POST) and variant 2 for updates (PUT), because variant 1 seems "cleaner" for creation but for update variant 2 would be better because it does not require a parentId (company or user)
Upvotes: 1
Views: 70
Reputation: 12839
First, REST is an architectur style not a protocol. This means that there is no right or wrong in how you define your URI. The only requirement Roy Fielding put in place was that each resource has to have a unique resource identifier (URI). The operation you may do on those URIs (verbs) are defined by the underlying hypertext transfer protocol (HTTP).
Second, there are certain best practices like using a sub-resource for resources that are embedded in other resources (especially if they can't exist without the parent resource) as in your case with addresses
and users
/companies
As you have certain issues with updating a sub-resource:
Usually to update a resource HTTP verb PUT
is used which has the limitation of replacing the current state (all the available data) with the state you've sent to the server (in case the update goes well). As there is no partial update yet defined in HTTP some use the PUT
verb a bit fuzzy and only update what is available within the request, though issuing a PATCH
request and only updating these fields is probably more correct in terms of HTTP specification.
Sub-resources are very similar to regular resources. If you update a sub-resource you don't need to update the parent resource. In your particular case, if you want to update a user's address but not the user itself, you issue a PUT /users/{userId}/addresses/{addressId} HTTP/1.1
request containing the new state of the address to the server. The request body may look like this:
{
"street": "Sample Street 1"
"city": "Sampletown",
"zip": "12345",
"country": "Neverland",
"_links": {
"self": { "href": "/users/{userId}/addresses/{addressId} }
"googleMap": { "href": "https://www.google.com/maps/place/Liberty+Island/@40.6883129,-74.042817,16.4z/data=!4m2!3m1!1s0x0000000000000000:0x005f3b2fa5c0821d" }
}
}
If you want to follow the HTTP PUT
verb closely and have dynamic fields, which may appear during runtime, you might have to alter the current table definition eventually, delete the old address entry and insert a new entry with the provided information (depending on the DB layer you are using SQL vs NoSQL). Note the HTTP PUT
verb semantic!
On utilizing a fuzzy update strategy (=partial update) a simple update statement should be fine. Here you can simply ignore the additional userId
contained within the URI, though this is not (yet) fully HTTP compliant - at least in regards to the spec. In that particular case it is your choice which version of URI you choose, though version 2 only works in the latter case while version 1 works in both cases.
Upvotes: 4