Grails Rest: Specify which GSON file to respond with on any action called - grails

I am trying to create REST web service with grails 5.1.7. Have checked the documentation for Grails REST on its official site and followed the steps to create services.
Currently got a situation where a webflow kind of feature needs to be performed, so to deal with we will be creating a single action which will handle session objects (which are to be transferred between steps of the webflow). Now the matter is how the GSON view will be resolved for each steps, as there will be single action will be serving all the steps of the webflow (there are 6 steps of the webflow). With HTML/GSP response of grails we can pass on "view" file to be used for any action. But for REST response, how to specify which GSON view should respond the result of the step?
I tried respond (just to experiment) (view: "handleDefineStep", model: modelMap), but it did not work. The document says that view and model should be used for HTML response so it is clear that it would not work.
One thing I would like to note that there is no domain classes in our project so domain rendering will not be there. Data are transferred using command objects created under src/main/groovy.
A sample code snippet for webflow is like:
def initializeFlow() {
// ... initialize some objects and store them to session to be used at other actions
def currentStep = params.step
switch(currentStep) {
case "step1":
handleStep1() // This action has its own GSON response to respond with
break;
case "step2":
handleStep2() // This action also has its own GSON response to respond with and likewise
break;
// ...
}
// ...
}
Update
handleStep1 method:
def handleStep1() {
// ...
respond (model, view: "editPage/handleDefineStep")
}

Related

How to prevent Grails from rendering the default view?

I'm using Grails 1.2.1. I have this method in my controller …
class SocialMediaCacheProxyController {
def index = {
def url = params.url
if (params.dumpAll != null) {
transportCacheService.processCacheDump(request.getRemoteAddr(), response)
} else if (url != null) {
doCacheTransport(request, response)
} // if
}
Problem is, both execution paths write content to the response. However, I think Grails is trying to render a page at the end of the index method, because I repeatedly get the below error after invoking this method …
1339754 [http-8080-4] ERROR org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/socialmediaproxy].[default] - Servlet.service() for servlet default threw exception
java.lang.IllegalStateException: response.getWriter() called after response.getOutputStream()
at org.codehaus.groovy.grails.web.sitemesh.GrailsPageResponseWrapper$GrailsBuffer.getWriter(GrailsPageResponseWrapper.java:284)
at org.codehaus.groovy.grails.web.sitemesh.GrailsPageResponseWrapper$3.activateDestination(GrailsPageResponseWrapper.java:125)
Any ideas how I can get Grails to stop rendering anything after my method is complete? Thanks, - Dave
If you don't tell Grails what to render, it will render based on convention. In your case, it is looking for an index.gsp. Controllers must return something. That's the whole point. So you can either use the convention and create an index.gsp that gets returned, or you can manually implement the render() method.
http://grails.org/doc/latest/ref/Controllers/render.html
It looks like most of the controller code that works with the ModelAndView keeps an eye on whether or not the ServletResponse has been committed.
I would posit that you could call response.flushBuffer() at the end of your controller action. This will cause the response to be marked as committed, and the controller will not return a ModelAndView.
An alternative would be to call response.outputStream.flush(), which would also result in the response being committed. This is what I usually end up doing after manually working with the response (e.g. for file downloads).
Note: I'm not sure where this falls within the realm of "best practices" - usually you're supposed to rely on the container to handle the flushing of the servlet streams. It's possible that there will be inadvertent side-effects by doing this. You'll probably have to test it out and see what happens with your app and the container you run it in.
I think you're trying to do something counter to the design of an MVC application. Controllers exist to send you somewhere based on parameters. Maybe you could look at using a Service instead, through an AJAX call. Or, if your controller action is changing data that you want to show, you could just redirect back to the page that the call came from. Start here:
http://grails.org/doc/1.0.x/guide/6.%20The%20Web%20Layer.html
http://grails.org/doc/1.0.x/guide/8.%20The%20Service%20Layer.html
I think Grails maybe forwarding to index.gsp, because it does so by default when you don't return a value.
Therefore, i think you should return null at the end of the index-closure to signal grails that you have already written everything you wanted to the output stream.
try this
render (view: "/the name of the page", model: [text:'hi there')
NB
if u want to render a template instead of "view" you put "template"

Scope of form variables in Grails

I am creating a Grails application which has an input page with text fields. Here the user can type in the data and on submit, the control goes to the action in controller.
Here I get the value of the form data using params.empName etc.
But the scope of this data is very small and doesnt get carried on if I do a redirect from the current action to another action.
Is there a way to increase the scope of the variables?
I am now to convert this to service oriented architecture. Therefore Is there a way to access these data in the service as well?
Please advice.
Thanks,
Megs
You can add...
params: params
...as an argument to the redirect, so that the incoming params are sent along with the redirect.
I don't think there's a built-in way to increase the scope. This is probably a Good Thing.
If you're redirecting in controllers, you should simply pass along the necessary parameters via the redirect() params dynamic property. Example:
def formHandler = {
// do stuff with params
redirect(action: 'anotherAction', params: params)
}
If you need scope to span multiple requests, e.g. if you're having a multi-step form entry given to the user, you might look into using web flows to persist state between requests.
For services, you're better off just passing down what you need as arguments to the service method, rather than exposing params. Example (similar to the Accessing Services section here):
// service
def myServiceMethod(def foo, def bar) {
// do stuff
}
// controller
def myService
def myControllerAction {
myService.myServiceMethod(params.foo, params.bar)
}
Exposing parameters from the controller to the service layer would break the layer-oriented approach Grails is trying to provide you; i.e. the "model" and "controller" components (of MVC) would be more tightly coupled.
I would also take a look at chaining actions as a way to pass the model information
http://www.grails.org/Controllers+-+Redirects

Using Pre/Post Spring-Security Annotations with Grails

I'm developing a Grails (Version 1.3.3) Web-Application using the Grails Spring-Security Plugin, Spring-Security-Core-1.0.1 (which, in turn, uses spring-security-3.0.2.RELEASE).
I would like to provide Spring-Security annotation-based access control on actions within a controller.
I have been able to successfully do basic authentication using the following annotations:
#Secured("hasAnyRole('ROLE_USER')")
def list = {
...
}
This works - providing access to the list action/view only to those with the ROLE_USER role.
However, the set of which roles are allowed to perform certain controller-actions may change over time and is a function of the system's overall state. That is, the set of roles allowed to perform a given action might be returned by a service or domain-object method.
One way I might be able to do something like this would be to use Spring-Security's "Expression Based Access Control" (#Pre and #Post annotations), something like the example at the Spring Security Documentation:
#PreAuthorize("hasPermission(#contact, 'admin')")
public void deletePermission(Contact contact, Sid recipient, Permission permission);
In this example for access control decisions, one can gain access to the objects sent to the method (eg contact) using the #contact syntax.
However, I can't get #PreAuthorize (or #RolesAllowed) annotations to work on a Grails controller-action. If I annotate the list action with #PreAuthorize (rather than #Secured, as above), I get the following error:
Annotation
#org.springframework.security.access.prepost.PreAuthorize
is not allowed on element FIELD
This isn't surprising -- the action is a Groovy closure (a field with executable code), rather than a method. However, I've also tried using the annotation on methods, called from the closure, like:
def list = {
testMethod()
....
}
#PreAuthorize("hasRole('ROLE_USER')")
public boolean testMethod(){
println "testMethod succeess"
return true;
}
While this doesn't throw any errors, it also doesn't appear to provide any access control. ("testMethod success" is printed whether or not the user has ROLE_USER).
So, I've tried a few different things (and read the documentation), but haven't been able to work out a nice way of using #PreAuthorize annotations with a Grails controller-action. Is this possible? Is there a better way in a Grails app to use Spring-Security-Annotations to provide access-control that is a function of the state of the system?
You need to use the ACL plugin to use those annotations, but they won't work on controller actions for the reasons you point out. #Secured works because I created a copy of the Spring Security annotation that allows it to be placed on fields as well as methods and classes, and I look for them and wire them up explicitly. You'll need to use annotated services that you call from your controllers.

How to I render validation results in a Grails Web Flow?

I have a Grails WebFlow that is similar to the following example:
def myFlow = {
init {
action {
def domain = MyDomain.get(params.id)
flow.domain = domain ? domain : new MyDomain()
}
on('success').to 'first'
}
first {
on('continue') {
flow.domain.properties = params
if(!flow.domain.validate()) {
return error()
}
}.to 'second'
}
...
}
Given this example, if a validation error occurs in the transition on('continue') in first:
What's the preferred way to set the model with the invalid domain object so I can use a <g:hasErrors>... in my view (like I would in a normal controller action)?
When I call error(), does it send the flow back to init or to first?
Does error() take any arguments (i.e. a model) that can be used for what I'm trying to accomplish (I can't find much documentation on the error() method).
I'd also take suggestions on how I could improve my flow states to better-facilitate handling these validation errors.
Summary: What's the preferred way to render validation errors within a Grails Web Flow?
-1
What's the preferred way to set the
model with the invalid domain object
so I can use a ... in my
view (like I would in a normal
controller action)?
You just need to return your domain object that has the errors. you can do that in an
action state
action {
user.validate()
return [user:user]
}
You can also set your errors in flash scope. On each transition Grails will copy the content of the flash scope into the ModelView and thus available in your gsp page
action {
flash.error = "your message"
}
-2
When I call error(), does it send the flow back to init or to
first? When you call error it call the
transition you defined for
You should define a handler for such as
on("error").to("handlerError")
Does error() take any arguments (i.e. a model) that can be used for
what I'm trying to accomplish (I can't
find much documentation on the error()
method).
I don't think so but you can do the following to set any variable when transitioning from one state to another
on("error") {
// do Something
}.to("handlerError")
3-
I'd also take suggestions on how I could improve my flow states to
better-facilitate handling these
validation errors.
I use flash for global and form errors but i needed ONE way to deal it. Currently with Grails the flash scope is managed differently in a flow than it's managed in a normal action. So I decided to write a little plugin to change the way the flash scope is handled in a flow and make it consistent with the way is managed in a normal action.
I a gsp page i can use my tags in the follwing way regardless of the action type (normal or flow)
<message:global />
or
<message:inline />
As for Form fields errors, i didn't like to deal with errors in domain objects. I wanted something more unified. So I decided to make them part of the http protocol and I have a javascript component the inject them into the form if i opt to. I found this solution much cleaner than dealing with g:errors each time.
-ken
I've found that one way to do it is to specifically invoke render() in the transition state, providing the model. Here's an example where only one field is validated:
first {
render(view: 'info', model: [flow.domain])
on('continue') {
if(!flow.domain.validate(['myField'])) {
return error()
}
}.to 'second'
}
One can then use <g:hasErrors> as follows:
<g:hasErrors bean="${domain}" field="myField">
<g:renderErrors bean="${domain}" as="list" field="myField"/>
</g:hasErrors>

Grails UrlMappings with .html

I'm developing a Grails web application (mainly as a learning exercise). I have previously written some standard Grails apps, but in this case I wanted to try creating a controller that would intercept all requests (including static html) of the form:
test 1
test 2
test 3
test 4
The intent is to do some simple business logic (auditing) each time a user clicks a link. I know I could do this using a Filter (or a range of other methods), however I thought this should work too and wanted to do this using a Grails framework.
I set up the Grail UrlMappings.groovy file to map all URLs of that form (/$myPathParam?) to a single controller:
class UrlMappings {
static mappings = {
"/$controller/$action?/$id?"{
constraints {
}
}
"/$path?" (controller: 'auditRecord', action: 'showPage')
"500"(view:'/error')
}
}
In that controller (in the appropriate "showPage" action) I've been printing out the path information, for example:
def showPage = {
println "params.path = " + params.path
...
render(view: resultingView)
}
The results of the println in the showPage action for each of my four links are
testJsp.jsp
testGsp.gsp
testHtm.htm
testHtml
Why is the last one "testHtml", not "testHtml.html"?
In a previous (Stack Overflow query) Olexandr encountered this issue and was advised to simply concatenate the value of request.format - which, indeed, does return "html". However request.format also returns "html" for all four links.
I'm interested in gaining an understanding of what Grails is doing and why. Is there some way to configure Grails so the params.path variable in the controller shows "testHtml.html" rather than stripping off the "html" extension? It doesn't seem to remove the extension for any other file type (including .htm). Is there a good reason it's doing this? I know that it is a bit unusual to use a controller for static html, but still would like to understand what's going on.
This is related to content negotiation, which you can read about in section 6.8 of the Grails user guide. If Grails recognises the extension as a particular type, the extension is removed from the URL and the type is added to the "format" parameter.
You can disable this behaviour by adding this entry to grails-app/conf/Config.groovy:
grails.mime.file.extensions = false

Resources