Graduated B.s.c Information System Engineering on BGU Uneversity (2004). Co-founded few startups in the domain of socail web. Been working on large cloud based ERP application in SAP for 7 years. Currently working as a development group manager in affiliation company. Gal is a DZone MVB and is not an employee of DZone and has posted 6 posts at DZone. You can read more from them at their website. View Full User Profile

RESTful Standard Resolved!

09.19.2012
| 8173 views |
  • submit to reddit

Lately I'm trying to build a web application which will be exposed in a RESTfull manner.
There are some general guideline and hints about how to define it, but no explicit standard or accepted schema structure to use.


After reading some info on the web, I think I manage to crack the pattern :-)
I would like to share the rules and structure I formed and hopefully to get some feedback about it and improve it, so please don't hesitate to leave notes and point any pain point that structure has.

The high level pattern is:
http(s)://server.com/app-name/{version}/{domain}/{rest-convention}

Where {version} is the api version this interface work with and {domain} is an area you wish to define for any technical (e.g. security - allow certain users to access that domain) or business reason (e.g. gather functionality under same prefix).

The {rest-convention} denotes the set of REST API which is available under that domain.
It has the following convention:

  • singular-resourceX/
    • URL example: order/  (order is the singular resource X)
      • GET - will return a new order
      • POST - will create a new order. values are taken from the post content body.
  • singular-resourceX/{id} 
    • URL example: order/1 (order is the singular resource X)
      • GET - will return an order with the id 1
      • DELETE - will delete an order with the id 1
      • PUT - will update an order with the id 1.  Order values to update are taken from the post content body.

  • plural-resourceX/
    • URL example: orders/
      • GET - will return all orders
  • plural-resourceX/search
    • URL example: orders/search?name=123
      • GET - will return all orders that answer search criteria (QBE, no join) -order  name equal to 123
  • plural-resourceX/searchByXXX
    • URL example: orders/searchByItems?name=ipad
      • GET - will return all orders that answer the customized query - get all orders  that associated to items with name ipad
  • singular-resourceX/{id}/pluralY
    • URL example: order/1/items/ (order is the singular resource X, items is the plural resource Y)
      • GET - will return all items that associated to order #1
  •  singular-resourceX/{id}/singular-resourceY/
  •  
    • URL example: order/1/item/
      • GET - return a new item (transient) that is associated order #1
      • POST - create a new item and associate it to order  #1. Item values are taken from the post content body.
  •  singular-resourceX/{id}/singular-resourceY/{id}/singular-resourceZ/
  •  
    • URL example: order/1/item/2/package/
      • GET - return a new package (transient) that is associated to item 2 (i.e. how to pack the item) and is associated to order #1
      • POST - create a new package and associate it to item #2 & order #1. package values are taken from the post content body.

One basically can have further nesting as long as the above convention is maintained and no plural resource is defined after another plural resource.
There are further guidelines/notes to make things clear:
- When using plural resource, the returning instances will be those of the last plural resource used.
- When using singular resource the returning instance will be the last singular resource used.
- On search, the returning instances will be those of the last plural entity used.

Hopefully your insight will help me improve this structure and overcome issues which you might came across.

In next post, after this suggested structure will be improved, I will try to give technical examples how to implement it using Spring MVC 3.1

 

Published at DZone with permission of Gal Levinsky, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Xavier Dury replied on Thu, 2012/09/20 - 2:21am

I don't think rest is only about URLs... what about Accept headers which make IMHO the salt of rest?

You could use specific Accept headers to version your api and leave that info out of your URLs:

Accept: application/vnd.my-api-v2.0+json 

or even better:

Accept: application/vnd.my-api+json; version=2.0

What do you think? 

Martin Spasovski replied on Thu, 2012/09/20 - 2:59am

I usually follow the way Backbone sync is working by default: http://backbonejs.org/#Sync

"The default sync handler maps CRUD to REST like so:

  • create → POST   /collection
  • read → GET   /collection[/id]
  • update → PUT   /collection/id
  • delete → DELETE   /collection/id"

I agree with you about putting the version and the domain in the URL, and with the other examples, you cracked the pattern :)

Putting versioning info in headers is OK, but almost everyone does it in the URL too.

I think that most importat think to keep in mind when building an API is to be understandable, reasonable and concise. And with REST that can be achieved pretty much.

 

Gal Levinsky replied on Thu, 2012/09/20 - 7:51am in response to: Xavier Dury

This is valid point and related more to a flavor rather to right or wrong, so I would present my considerations for putting it in the url:

- Readability. one of the REST principles is human readable URL. If version id is important enough info then putting it in the URL would make it more clear for the person who use it and avoid issues which might occur due to wrong version usage.

- Discovery. Another principle is the ability to find "places" in the app by changing easily url parameters. using the version in the URL will make it easy for the user to search and browse through version, w/o changing the code or use browser plugin.

- Google do it.  ;-)  

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.