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.