Search code examples
restrestful-architecturehttp-verbs

REST: How to update a row and create zero or more of other resource on same request?


I'll try to make this as simple as possible, it may be sort of dumb question.

I'm rewriting an 7 years old web application (help desk software). It is required to make it a REST API to be consumed by different clients web browser and mobile app. Also required to keep the business logic as close as possible to the original which for now have been working well.

The current struggle about REST:

What I need is to update the a resource lets say /tickets/47321

If the status_id of the this resource is changed a record of this change need to be saved, both in the same DB transaction because it need to be all-or-nothing. this is how the original application worked and we would like to keep this behavior.

So question is:

Can I PUT to tickets/47321 the whole resource or partial state representation to update the resource residing in server and create the new record of the history change (if status_id is different) and return them both back to client as JSON:

 {
    ticket: {}, // new ticket state
    history: {} // the new created record of history change 
 }

This way the client can update the ticket and add the history to a list of history changes if there is any being return?


Solution

  • Technically, yes, you can do this. However, it might not be as straightforward as simply returning 2 objects, side by side; looking at the Richardson Maturity Model (Level 1), one would expect to receive the same type of resource after calling (PUT) an api endpoint.

    That being said, you could either embed the additional resource (append a history change to a ticket, following the Hypertext Application Language (HAL) proposed draft specification), or better yet (if you're aiming towards REST level 3), provide a link relationship, in conformity with the "Target IRI" defined in Web Linking specification (RFC 5988) from the ticket:

    • /api:history?ticketId=47321 would return all the history records belonging to that ticket, paged and sorted by created date, for example (and you can just select the latest)
    • /api:history?id=123 you would do some work on the server to ensure this points straight to the latest history record (related to that ticket id)

    Regarding the partial update, looking at the RFC 6902 (which defines the Patch standard), from the client's perspective the API could be called like

    PATCH /ticket/47321
    
    [
        { "op": "replace", "path": "/author", "value": "David"},
        { "op": "replace", "path": "/statusId", "value": "1"}
    ]
    

    More examples can be found here.