As I get more into RESTful APIs, the (good) simplicity of the approach means that you generate a LOT of boilerplate code, and code that has to match in three or four different places, e.g. for a Jersey-based stack:
HTML on the web page which provides controls (a button Create Foo)
JS on the web page which formulates the JSON and the request to create a Foo
A FooRest class method to handle the request and create a Foo
A Foo class to instantiate, which will manipulate the data structure
Are there tools which provide a starting point for some or all of this code automatically, possibly starting from something straightforward like a JSON data structure? E.g., provide:
card: {
methods: [GET],
}
handOfCards: {
methods: [GET POST PUT DELETE],
}
and at the very least end up with Ajax requests, CardRest and HandOfCardsRest classes with the specified methods stubbed out, and Card and HandOfCards classes with properties or getters/setters?
Have you tried Backbone.js? It is a JavaScript library that handles REST Ajax requests for you. It allows you to define your models to wrap the data and provides setters, getters, save and delete functions, etc.
It also allows you to bind the models to views which generate the UI HTML.
I think nearly any *rails application does all of this for you. Grails is my favorite right now, and once you get the initial setup done (a single command) you create domain classes with another command.
Once those are created, you can generate both views (html) and controllers for handling all of these actions with a single command, and the boiler plate is sufficient for a lot of initial sites. It will even create test cases for you, although you'll need to define what the actual tests do. You can program it by convention very easily, or create your own mappings from URLs -> controller actions. It has a ton of plugin support and easily handles remote submission of forms (via javascript) built in.
It doesn't take a json data structures for creation, but the domains are very easily created (using groovy) and it autowires getter/setters, service injections, etc as it is based on the Spring Framework.
Your goal should probably not be code generation of boilerplate but actually writing less code.
Spark is a Java micro web framework based on Sinatra.
Here's some example code:
import static spark.Spark.*;
import spark.*;
public class HelloWorld {
public static void main(String[] args) {
get(new Route("/") {
#Override
public Object handle(Request request, Response response) {
// .. Show something ..
}
});
post(new Route("/") {
#Override
public Object handle(Request request, Response response) {
// .. Create something ..
}
});
put(new Route("/") {
#Override
public Object handle(Request request, Response response) {
// .. Update something ..
}
});
delete(new Route("/") {
#Override
public Object handle(Request request, Response response) {
// .. annihilate something ..
}
});
options(new Route("/") {
#Override
public Object handle(Request request, Response response) {
// .. appease something ..
}
});
}
}
An alternate (or addition) to Juan's answer, you might want to check out Knockback.js , which takes the best of Knockout and adds the best of Backbone.js . Backbone has support for RESTful API's via it's "sync" functions. Quoting their website:
The method signature of Backbone.sync is sync(method, model,
[options])
method – the CRUD method ("create", "read", "update", or "delete")
model – the model to be saved (or collection to be read)
options – success and error callbacks, and all other jQuery request options
You might want to try a different approach altogether and try somethink like project lombok. It will at least let you nix all your getters and setters.
Related
I am working on designing a common Service interface for atleast 5 concrete implementations. Now all these services require different types of inputs. I thought of creating a Param class to hold parameters, so that interface could remain common. but then, for some implementations, some of the fields will be unused. I also thought of using Map to hold my params, but that is also not good(casts and if-elses everywhere). Also, I thought of doing was to create a class with Static methods Service.responseAsPerFirstImplementation(p1, t1, i1) and such. But, this way is not good coding. Please suggest how I should design between Modular design, flexibility vs variability of parameters?
EDIT:
Is below the good way of doing it?
public class Client {
public static void main(String[] args) {
System.out.println(Services.response(new UserParam(1, new Date())));
System.out.println(Services.response(new PatternParam("core")));
}
}
I think the core of the question is if your parameters come from some "generic", unstructured sourcelike HTTP request parameters or command line arguments or some structured source - I would put a Swing form there as you know in advance which UI elements you have.
In case of "generic" parameters you have to convert these parameters into something your services can process. You can do this manually or with some library/framework. For instance, you can use annotations to describe how your HTTP request and its parameters map to your controllers/services/methods:
#RestController
#RequestMapping("/trainRun")
public class TrainRunController {
#RequestMapping(value = "/{year}/{month}/{day}/{trainNumber}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public TrainRun getTrainRun(#PathVariable Integer year, #PathVariable Integer month, #PathVariable Integer day,
#PathVariable String trainNumber) { ... }
}
Similarly with command-line parameters - you can use somethings like args4j to map CLI parameters into Java object first and then call your services appropriately.
Hope this helps.
It's RESTful web app. I am using Hibernate Envers to store historical data. Along with revision number and timestamp, I also need to store other details (for example: IP address and authenticated user). Envers provides multiple ways to have a custom revision entity which is awesome. I am facing problem in setting the custom data on the revision entity.
#RevisionEntity( MyCustomRevisionListener.class )
public class MyCustomRevisionEntity extends DefaultRevisionEntity {
private String userName;
private String ip;
//Accessors
}
public class MyCustomRevisionListener implements RevisionListener {
public void newRevision( Object revisionEntity ) {
MyCustomRevisionEntity customRevisionEntity = ( MyCustomRevisionEntity ) revisionEntity;
//Here I need userName and Ip address passed as arguments somehow, so that I can set them on the revision entity.
}
}
Since newRevision() method does not allow any additional arguments, I can not pass my custom data (like username and ip) to it. How can I do that?
Envers also provides another approach as:
An alternative method to using the org.hibernate.envers.RevisionListener is to instead call the getCurrentRevision( Class revisionEntityClass, boolean persist ) method of the org.hibernate.envers.AuditReader interface to obtain the current revision, and fill it with desired information.
So using the above approach, I'll have to do something like this:
Change my current dao method like:
public void persist(SomeEntity entity) {
...
entityManager.persist(entity);
...
}
to
public void persist(SomeEntity entity, String userName, String ip) {
...
//Do the intended work
entityManager.persist(entity);
//Do the additional work
AuditReader reader = AuditReaderFactory.get(entityManager)
MyCustomRevisionEntity revision = reader.getCurrentRevision(MyCustomRevisionEntity, false);
revision.setUserName(userName);
revision.setIp(ip);
}
I don't feel very comfortable with this approach as keeping audit data seems a cross cutting concern to me. And I obtain the userName and Ip and other data through HTTP request object. So all that data will need to flow down right from entry point of application (controller) to the lowest layer (dao layer).
Is there any other way in which I can achieve this? I am using Spring.
I am imagining something like Spring keeping information about the 'stack' to which a particular method invocation belongs. So that when newRevision() in invoked, I know which particular invocation at the entry point lead to this invocation. And also, I can somehow obtain the arguments passed to first method of the call stack.
One good way to do this would be to leverage a ThreadLocal variable.
As an example, Spring Security has a filter that initializes a thread local variable stored in SecurityContextHolder and then you can access this data from that specific thread simply by doing something like:
SecurityContext ctx = SecurityContextHolder.getSecurityContext();
Authorization authorization = ctx.getAuthorization();
So imagine an additional interceptor that your web framework calls that either adds additional information to the spring security context, perhaps in a custom user details object if using spring security or create your own holder & context object to hold the information the listener needs.
Then it becomes a simple:
public class MyRevisionEntityListener implements RevisionListener {
#Override
public void newRevision(Object revisionEntity) {
// If you use spring security, you could use SpringSecurityContextHolder.
final UserContext userContext = UserContextHolder.getUserContext();
MyRevisionEntity mre = MyRevisionEntity.class.cast( revisionEntity );
mre.setIpAddress( userContext.getIpAddress() );
mre.setUserName( userContext.getUserName() );
}
}
This feels like the cleanest approach to me.
It is worth noting that the other API getCurrentRevision(Session,boolean) was deprecated as of Hibernate 5.2 and is scheduled for removal in 6.0. While an alternative means may be introduced, the intended way to perform this type of logic is using a RevisionListener.
My service:
#POST
public String setData(#QueryParam("id") Long is, MyObject payload) {
...
}
or
#POST
public String setData(#PathParam("id") Long is, MyObject payload) {
...
}
My interceptor on the server:
Object read(MessageBodyReaderContext context) throws IOException, WebApplicationException {
Class mypayloadtype = context.getType;
InputStream mypayloadinpustream = context.getInputStream();
Long myidparam = ???????? // how to get the query or path param here?
}
EDIT: To be a bit more concrete:
What I'd like to do is to grab the XML and store it based on the parameters in a separate audit system. Maybe PreProcessInterceptor / PostProcessInterceptor are the better choices?
Any hints or alternative ways to get the param when the xml is still available for preprocessing?
Miguel
I just stumbled over the same problem today. I needed the #PathParams and #QueryParams in the read() method and ended up with something like this:
public class MyInterceptor implements PreProcessInterceptor, MessageBodyReaderInterceptor
{
private static ThreadLocal<UriInfo> uri = new ThreadLocal<UriInfo>();
public ServerResponse preProcess(HttpRequest request, ResourceMethod method)
{
uri.set(request.getUri);
...
}
public Object read(MessageBodyReaderContext context)
{
String param = uri.get().getPathParameters().getFirst("myidparam");
...
}
}
Although when thinking about it now - I'm not quite sure, if just using PreProcessInterceptor/PostProcessInterceptor will also do the trick for my (and maybe your) problem. I'll have another look tomorrow.
I am not an expert on the topic but to me it seems as if the MessageBodyReaderContext interface does not really know if it is on the server or the client side, so it cannot expose the request or its parameters / path parts etc.
So as far as I know this is not possible.
If your code knows that it lives on the server side of the rest
communication, maybe you can use a servlet filter to store the request
in a ThreadLocal and then access it from there while the request is
handled, somewhat similar to RequestContextFilter / RequestContextHolder from the spring framework? (Then the request object does not know anything about the annotations of your service, but instead one has to extract the information manually from the request. This means to have the same information in two places, so there has to be a better solution ...)
Edit: after looking at some examples I get the vague feeling that if you want to read the input stream to create an object and add path parameters to it, MessageBodyReaderInterceptor is simply not the way to go. Instead set up a MessageBodyReader which constructs the object from the request body data, and this then will be passed into the public String setData(#PathParam("id") Long is, MyObject payload), assuming that this method is annotated with a #Consumes which matches the #ConsumeMime annotation for the MessageBodyReader. There you might be able in the setData to set the missing id on the object read from the request body. Some examples related to this seem to be here: How to get full REST request body using Jersey? (but for Jersey, not jBoss :-/)
However I am not sure if that works for you, and I also feel I completely overestimated my ability to answer this question appropriately, so I hope someone more knowledgeable comes in with a better solution.
On the server side I want to know how to access data used in an RPCRequest from SmartGwt.
Here is the SmartGwt client code:
private void update() {
RPCRequest request = new RPCRequest();
request.setData("RPC text from client");
request.setActionURL("/Empi-MT/resources/empi/update");
request.setContentType("text/xml");
RPCManager.sendRequest(request,
new RPCCallback() {
public void execute(RPCResponse response, Object obj, RPCRequest request) {
SC.say("Response from the server:" + obj);
}
});
}
Here is the RESTful java server code .
#POST
#Consumes("text/xml")
#Produces("text/xml")
#Path("/update")
public String update() {
return "We got to here";
}
This trivial code works fine, but now I need to know how to access the data that was put into the RPCRequest. How do I do that in the server code?
Thanks,
You look like you may be heading in the wrong direction; if this "update" operation is a CRUD operation on some object, you want to using DataSources - take a look at the QuickStart overview of Data Integration, focusing on RestDataSource.
http://www.smartclient.com/releases/SmartGWT_Quick_Start_Guide.pdf
Also you seem to be starting down the road of using generated REST services, this is almost always wrong - see this FAQ:
http://forums.smartclient.com/showthread.php?t=8159#aExistingRest
Finally if this really is not a CRUD operation, you want to set useSimpleHttp on the RPCRequest, and then the docs for this property explain the different ways data can be sent.
http://www.smartclient.com/smartgwtee/javadoc/com/smartgwt/client/rpc/RPCRequest.html#getUseSimpleHttp()
I have a controller with a method that handles incoming GET data, stores some things in the model, and then redirects to another page that deals with these objects.
I can't seem to find any good way of getting the object stored in the first method back out of the model to use in the second method. How can I do this?
Here's the top of the controller:
#Controller
#RequestMapping("/reviews")
#SessionAttributes({"review", "externalReview"})
public class ReviewController {
// [SNIP]
}
Here's the code that adds the objects I'm after to the model:
#RequestMapping(value="/new", params="UName", method=RequestMethod.GET)
public String newFormFromExternal(#ModelAttribute("externalReview") ExternalReview externalReview, Model model) throws IncompleteExternalException {
// Convert the inbound external
Review fromExternal = ExternalReviewUtil.reviewFromExternalReview(externalReview, externalDAO);
// Add the externalReview to the session so we can look to see if we got a reviewee on the way in
model.addAttribute("externalReview", externalReview);
model.addAttribute("review", fromExternal);
return "redirect:/reviews/newFromExternal";
}
You are in luck.
If you are using or have ability to update to the newly released Spring 3.1, you can make use of the newly scoped Flash variables.
http://static.springsource.org/spring/docs/3.1.0.RC1/spring-framework-reference/html/mvc.html#mvc-flash-attributes
If you can't use 3.1, you probably can implement the solution yourself. Essentially you want to capture the model object required to be present in the redirect, put in the session, and remove it once it is retrieved to keep your session from bloating.
Currently, I'm just getting a Map of the model, getting the object I want out by it's key (the String name), and then casting it to the object it really is (rather than just Object).
Here's the code:
#RequestMapping(value="/newFromExternal", method=RequestMethod.GET)
public String newExternalForm(Model model) {
// Get the review from the model
Review review = (Review) model.asMap().get("review");
/*** Do stuff with the review from the model ****/
return "reviews/newFromPacs";
}
This way works, but it seems hacky and clunky. Is this really the only way?
One possible solution is to use #ModelAttribute, though it's quite ugly since you'll need to disable databinding for that attribute (for security):
#RequestMapping(value="/newFromExternal", method=RequestMethod.GET)
public String newExternalForm(#ModelAttribute Review review) {
...
}
#InitBinder("review")
public void disableReviewBinding(WebDataBinder b) {
b.setAllowedFields();
}