Ole Albers
Ole Albers

Reputation: 9305

correct REST approach for hierarchy Inserts and Updates

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

Answers (1)

Roman Vottner
Roman Vottner

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

Related Questions