REST actions and URL API design considerations

RestArchitectureServicestack

Rest Problem Overview


I'm building a inventory management system and I'm busy designing (thinking) of the API and my REST implementation.

I have the following resources and on the resource you can perform many actions/operations. Each operation will modify the resource and in some cases create a new resource and also create history or transactions.

I'm looking for some input from experts in regards to useability and acceptability in regards to URL and resource design. The gotchas and real world examples, any opinion or criticism welcome.

My concerns are that the whole application might be develop around this one big resource? My backend stack will be C# and servicestack framework and for frontend I'll be using HTML and AngularJS. Not that it makes a difference.

Scenario 1. Typical operation will be:

POST /inventory/{id}/move
POST /inventory/{id}/scrap
PUT  /inventory/{id}/takeon
POST /inventory/{id}/pick
PUT  /inventory/{id}/receive
POST /inventory/{id}/hold
POST /inventory/{id}/release
POST /inventory/{id}/transfer
POST /inventory/{id}/return
POST /inventory/{id}/adjustment


{
  "userID": "",       //who is doing the actions (all)
  "tolocationID": "", //new location for inventory (move/takeon/pick/receive/transfer/return)
  "qty": "",          //qty (pick/receive/takeon/transfer/return)
  "comment": "",      //optional for transaction (all)
  "serial": "",       //(takeon/receive)
  "batch": "",        //(takeon/receive)
  "expirydate": "",   //(takeon/receive)
  "itemCode": "",     //(takeon/receive)
  "documentID": "",   //(pick/receive/return/transfer)
  "reference" :"",    //(all)
  "UOM" :"",          //(all)
  "reference" :"",    //(all)
}

Is this acceptable in regards to standards. The other approach might be.

Scenario 2.

POST /inventory/{id}/move
POST /inventory/{id}/scrap
PUT  /inventory/{id}/takeon
POST /document/{id}/pick     //**document**
PUT  /document/{id}/receive  //**document**
POST /inventory/{id}/hold
POST /inventory/{id}/release
POST /document/{id}/transfer  //**document**
POST /document/{id}/return    //**document**
POST /inventory/{id}/adjustment

and then to change the resources.

Scenario 3. in my opinion wrong

POST /transaction/move/{...}
POST /transaction/scrap/{...}
PUT  /transaction/takeon/{...}
POST /transaction/pick/{...}  
PUT  /transaction/receive/{...} 
POST /transaction/hold/{...}
POST /transaction/release/{...}
POST /transaction/transfer/{...}  
POST /transaction/return/{...}
POST /transaction/adjustment/{...}

Any comments welcome, not looking for answer but more advice on design considerations?

Thanks for taking the time reading this entry!

Rest Solutions


Solution 1 - Rest

Short answer:

Use actions at the end of the url to change state.

Github does it like this to star a gist: PUT /gists/:gist_id/star

Explained here https://developer.github.com/v3/gists/#star-a-gist

Long Answer:

Your objective is making your applications effortless to use an intuitive. Your users should use your app in the simplest possible way. Your users should not suffer the limitations or hard guidelines of the technologies you use.

So actions and operations are inherently not resources, but actions over resources. So they will not respond to a "resource to URI mapping" like REST is.

But you can use the best of REST, and still the best of URIs, combining both.

Remember:

The technology should work for you, and not you for the technology.

If you become an slave of technology, you will end up creating unusable applications or using ugly technologies like XML or Java Home and Remote interfaces, so you end up writing 5 files to create a hello world application.

BEWARE of the "shiny object syndrome". Google it.

Not because a technology is new or is "the new way of doing things", it means that is a good technology or you need to get distracted and let aside all other technologies to succumb to REST.

Take what you need from the technology and then make the technology work for you.

Using REST api does not mean you need to discard the capabilities of the URL and URI technologies.

References: https://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api#restful

Solution 2 - Rest

> I have the following resources and on the resource you can perform > many actions/operations. Each operation will modify the resource and > in some cases create a new resource and also create history or > transactions.

Fundamental to the REST architectural schema is the idea of using the HTTP verbs as the only verb, and not including verbs in your URLs. In your shoes, I would consider reworking your system to remove the verbs. It's hard to suggest a design without actually knowing what any of the verbs mean, but perhaps something closer to:

GET /inventory/{id}
PUT /inventory/{id} -- update with new location 
PUT /inventory/{id} -- update with new status (scrapped)

etc .. That's a more RESTful approach. Many of these actions look like they're really just PUTs that update multiple properties of the resource, such as location, quantity, comment field, etc. And perhaps scrap is DELETE? Hard to tell.

Another option would be to use POST, where the body includes the instructions for how to operate on the inventory item:

POST /inventory-transactions/{id}
{
    "action": "takeon",
    "newLocationId": 12345,
    ...
}

This gives you a lot of traceability, because every operation can now be tracked as a resource. The down side is a lot of complexity around the endpoint.

You can also break out some of the "verb" operations into resources:

POST /returned-inventory
{
    "inventoryId": 12345,
    "documentId": 67890,
    "comment": "Busted up",
    ...
}

This lets you easily look at inventory items by their status, which may or may not be helpful. You could, for instance, call GET /returned-inventory?documentId=67890 to get back all the returned items from the same document.

Hopefully there's some food for thought in there. It's really not going to be possible for anybody to tell you the "right" thing to do without knowing your business requirements in greater detail.

Solution 3 - Rest

"Restful Objects", which defines a RESTful API, states that actions are valid.

Available actions can be discovered, enabled/disabled, and can give 'disabled reason' feedback.

Actions are 'invoked' using GET (query), PUT (idempotent), or POST(non idempotent)

Restful Object Spec (page C-125)

Solution 4 - Rest

My considerations about the following example:

POST /inventory/{id}/move
  1. The "move" term can be considered as a shortening for "move-request".
  2. In this case, the user is posting a request to move the inventory.
  3. When accepted, the request will trigger the corresponding server action.
  4. A request is some kind of resource, it can even be persisted by the server for history purposes or to trigger asynchronous tasks if not executed immediately.

Those are the main reasons why I consider that verbs can be used at the end of URIs without breaking any REST guidelines.

Another considerations:

  1. Make sure you're using this "request abstraction" only in cases where you don't have a a simple resource that can be posted or put.
  2. PUT inventory/{id}/manager is a better approach than POST inventory/{id}/set-manager, unless your request requires some params that are not properties of manager.
  3. In cases where your params doesn't fit an entity / valueobject properties, a POST inventory/{id}/manager-update would be recommended, which is, clearly, a resource.

Finally ... most of the REST guidelines examples covers only CRUD applications. Richer domains need more expressive abstractions than just use simple nouns from domain entities or value objects.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFrancois TaljaardView Question on Stackoverflow
Solution 1 - Rest1P0View Answer on Stackoverflow
Solution 2 - RestEric SteinView Answer on Stackoverflow
Solution 3 - RestPatrickView Answer on Stackoverflow
Solution 4 - RestTPaimView Answer on Stackoverflow