Friday, February 08, 2013

REST-JSON Service Definition Simplified...


In continuation to my previous post on REST-JSON Service Versioning here are my thoughts around service definition for REST-JSON.
Problem Statement:
As a service provider, one is obliged to document service contract (request/response) of the service exposed to consumers.
If you take SOAP/web-service world for an analogy, WSDL acts as a contract for the services exposed. This article is an attempt to see how a JSON schema can be exposed via a generic services/wrappers.
Note: I have chosen Spring MVC + Jackson Library as software stack for the solution approach.
Ex:
1.  Let’s taken an example of Service below that returns an employee object, given an employee Id.
@Controller
public class TestController {
 
 @RequestMapping(value="/employee", method=RequestMethod.GET)
 public ResponseEntity fetchEmployee(){
  Employee employee = new Employee();
  return new ResponseEntity(employee, HttpStatus.OK);
 }
 
   }
2.  The Employee response object could look something like this,
public class Employee {
private int employeeId;
private String name;
private long primaryNumber;
 
 public int getEmployeeId() {
  return employeeId;
 }

 public String getName() {
  return name;
 }

 public long getPrimaryNumber() {
  return primaryNumber;
 }
}
Solution:
Based on the problem statement, the solution proposed below would seamlessly discover the REST-JSON services exposed in your application.
1.  To do so, I have introduced an implementation/overridden class on top of Json Serialize/De-Serialize - DiscoverableService.java
/**
 * Extending DiscoverableService means the exposed service is enabled for auto
 * discovery.
 */
public abstract class DiscoverableService {

 /**
  * @return
  */
 public List getAllExposedServiceInfo() {
  
  . . . . 
 }
}
2.  Now any new service developed should extend DiscoverableService.java, to mark itself as exposed service for service discovery.
@Controller
public class TestController extends DiscoverableService {
 
 @RequestMapping(value="/employee", method=RequestMethod.GET)
 public ResponseEntity fetchEmployee(){
     Employee employee = new Employee();
       return new ResponseEntity(employee,HttpStatus.O)
 }
}
3.  I have a controller/service exposed for the service discovery information, which is ServiceController.java.
Spring Auto wires all the controllers in the context that extend DiscoverableService to this controller class as shown below.
@Controller
public class ServiceController {

@Autowired
protected List discoverableServices; 

@RequestMapping(value = SERVICE_NAME, method = RequestMethod.GET)
public synchronized ResponseEntity> fetchAllServiceInfo() {
 List serviceInfos = new ArrayList();
 for (DiscoverableService service : discoverableServices) {
  serviceInfos.addAll(service.getAllExposedServiceInfo());
 }
 return new ResponseEntity>(serviceInfos,
    HttpStatus.OK);
}

}. . . . 
4.  Now comes the simple & final step, access your service information
http://localhost:8080/web-context/service/employee will return service definition for fetchEmployee service.
[{
"serviceURI": "/employee",
"requestMethod": ["GET" ],
"methodName": "class com.sample.controller.TestController.fetchEmployee()",
"request": [ ],
"response": {
"employeeId": 0,
"name": null,
"primaryNumber": 0
}}]
5.  http://localhost:8080/web-context/service  - returns definition of all services exposed by the system.
Conclusion:
With the above approach, exposing service/contract definition to consumer will be seamless.  Just sharing the service definition to the service consumer would do the trick.

2 comments:

Gerard Davison said...

Hi,

Can I ask why you didn't consider a mapping of WADL to JSON instead of creating your own description?

Also why you didn't make sure of the OPTIONS method to return a service definition and instead use an OOB URI to gather this information?

Thanks,

Gerard

Disclosure I have just been working on JSON/WADL and JSON-Schema generation for the Jersey project

Senthil Balakrishnan said...

Appreciate your comments.

As it sounds to me WADL is more of declarative, the approach I was trying to suggest is to pick the service definitions from the Annotations dynamically. And remove the hassles of .xml definition/declaration.