Skip to main content

Designing and Testing RESTful web services [ UML, REST CLIENT ]

Posted by lamine_ba on June 22, 2012 at 2:23 PM PDT

If you know the enemy and know yourself, you need not fear the result of a hundred battles.
If you know yourself but not the enemy, for every victory gained you will also suffer a defeat.
If you know neither the enemy nor yourself, you will succumb in every battle.
Sun Tzu, Chinese general. The Art of War

INTRODUCTION

Ladies and Gentlemen, Like you, I'm intimately convinced that a professional should not promote a bad practice or a bad technology even though it does serve his own interests or those of his company. And that is one reason why, I wrote this blog post as a replacement of my previous one in which I have shown to many of you, how to build a JAX-RS web service with Groovy. But believe it or not, but I did really ask to myself how I did ever think that giving you the knowledge of a scripting language or whatever to write your RESTful web service, could be the key for you to understand how to design a successful RESTful API.

IT IS ALL ABOUT CONSTRAINTS, RESOURCES, URIS, METHODS, REPRESENTATIONS

Then let's repair our mistake and let's first start by the definition of REST itself. REST which stands for REpresentational State Transfer is not by itself an architecture but rather a set of constraints that when applied to the design of a system, creates a software architectural style that is maintainable, extendable, and distributed. So in simple words, following the guidelines outlined in Roy Fielding's work means leading one to the point of having some specifics requirements that he has to adhere to in order to design a RESTful system. And below is a summary of these requirements that we must all comply with.

  • It must be a client-server system
  • It has to be stateless
  • It has to support a caching system
  • It has to be uniformly accessible
  • It has to be layered to support scalability
  • And optionally, it should provide code on demand

RESOURCES + URIS

Whenever you see yourself writing this kind of code in whatever language, with whatever technology and with whatever framework that does support the REST style

  1. @Path("/customers")
  2. class CustomerResource {
  3.  
  4. }

Instead of this kind of declaration :

  1. @Path("/customers")
  2. class CustomerService {
  3.  
  4. }

Just learn from your UGLY mistake that you have not yet fully understood what the generic term of a "Resource" does mean. To keep it simple, a RESTful resource is nothing more than a logical and temporal mapping to a concept in the problem domain for which we are implementing a solution. In other words, the resources are the entities of the domain model. So the key thing in your mastery of the REST art is to focus on them and mainly on their associations because they are the ultimate guidance to how to meaningfully design your URIS right and by the way, let me reveal you that an association is definitely a fragmentation, a different navigation to a different path. So you have to remember this, as you have to remember that there is no way for a possible change of your URIS once they are publicly available. So I STRONGLY advice you to take your time in your design process.

DOMAIN MODEL

URIS + METHODS = REPRESENTATIONS

And if you have been fully blessed to have fully understood that an URI cannot live without the method that will describe the type of operation we can perform on it, yes for sure, you have made a huge step forward in your learning process. Otherwise, I think it would be better if we could move away from all of this insane theory and start putting things into practice. And maybe we can take again the Customer Resource as an example?

URI HTTP METHOD DESCRIPTION Representation
/customers GET Retrieve the list of Customers [json, xml]
/customers POST Create a Customer [json, xml]
/customers PUT Update a Customer [json, xml]
/customers/{id} GET Retrieve a Customer [json, xml]
/customers/{id} DELETE Delete a Customer [json, xml]
/customers/import POST Import a list of Customers [json, xml]
/customers/{id}/contacts GET retrieve the Contacts of a Customer [json, xml]

IMPLEMENTATION

In your implementation, you can use whatever language you want, REST can bypass this barrier. And myself, I personally use Java for my unshareable services and regarding the others, believe it or not, but I was very close to use Scala today or any other compilable scripting language in a very neutral way of course if the JSR 223 was up to date and of course if the ScripEngine class was able to resolve the dependencies of a Script. But sadly, its eval method does take a FileReader and a String as parameters, Can one believe it? So until we find a way to do it ourselves, let's just have some fun with Groovy.

  1. @Path("/customers")
  2. class CustomerService {
  3.        
  4.         @GET
  5.         @Produces([MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML])
  6.         def List<Customer> getCustomers() {
  7.             dao.customers
  8.         }
  9.        
  10.         @POST
  11.         @Produces([MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML])
  12.         @Consumes([MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML])
  13.         def Customer createCustomer(Customer customer) {
  14.             dao.createCustomer(customer)
  15.         }
  16.        
  17.         @PUT
  18.         @Produces([MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML])
  19.         @Consumes([MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML])
  20.         def Customer updateCustomer(Customer customer) {
  21.             dao.updateCustomer(customer)
  22.         }
  23.        
  24.         @GET @Path("{id}")
  25.         @Produces([MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML])
  26.         def Customer getCustomer(@PathParam("id") long id) {
  27.             dao.getCustomer(id)
  28.         }
  29.        
  30.         @DELETE @Path("{id}")
  31.         @Produces([MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML])
  32.         def Customer deleteCustomer(@PathParam("id") long id) {
  33.             dao.deleteCustomer(id)
  34.         }
  35.        
  36.         @POST @Path("import")
  37.         @Consumes(["multipart/form-data"])
  38.         @Produces([MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML])
  39.         def List<Customer> importCustomers(InputStream stream){
  40.             dao.importCustomers(stream)
  41.         }
  42.        
  43. }

DEMONSTRATION

You can find an update of this module deployed in my application on the outstanding CloudBees PAAS at this url so that you can download it. And if you were really fully blessed to have my invisible runtime, yes for sure you would be able to run it locally and to customize it. But in this present time, while I'm eagerly waiting to collaborate with ALL of YOU, through REST, the better thing we can do is to just play around with it and have some fun discovering the goodies I came with today.



Whenever you click on the WADL button, an ajax request with the OPTIONS method is sent behind the scenes to your service to discover its whole capabilities. And from this awesome material, my crazy little brother did have the silly inspiration to build with the HTML5 canvas, a class diagram that will help you visualize your entities and their relationships

And myself like an old guy, I did have the ridiculous inspiration to build a generic and pluggable Rest Client that will help you test and debug your web services.

CONCLUSION

And all of that coming to YOU without writing a single line of Java code and without running a STUPID lifecycle of six phases. Wooow! It is clearly established now from my personal perspective that JavaScript is definitely the FATHER of Java on the web. So Ladies and Gentlemen, TAKE IT REALLY LIKE IT IS and also WHATEVER YOU MAY SAY, IT'S REALLY TRUE that my insane words are those of a TRUE JAVA advocate and YES FOR SURE, A PROFESSIONAL SHOULD DIE POOR RATHER THAN BEING OVERPAID TO DESIGN AND WRITE BULLSHIT...



twitter : lamine_ba

 

AttachmentSize
classdiagram.PNG103.92 KB
demo.png10.07 KB
classdiagram2.PNG111.98 KB
restclient.PNG38.38 KB

Comments

You're clearly missing some major architectural points here. ...

You're clearly missing some major architectural points here. You do indeed spread "insane words"...

I'm really eager to read the major architectural points I'm ...

I'm really eager to read the major architectural points I'm clearly missing here. Please tell me really what it is since JavaScript is only used to build and enhance the dynamic of my View. If you tend to think that Java can do everything, that is where the first architectural mistake starts. And MVC means something else on the web and REST is definitely the real nature of the WEB. So keep your server RESTFUL, that's the only advice I can give you. And tomorrow, If I have the goal to build a mobile or a desktop client, be sure that I will not come with the word JavaScript and a web framework should never have the pretension to abstract the whole web. It will lead to what Joel Spolsky called a Leaky Abstraction. Words can be insane and true at the same time. Let's just let people make their own impression instead of forcing them our vision. Let's just let them take the way they want to make their own discoveries....