Few questions about handlers...

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Few questions about handlers...

robert
1. Order of handlers do matter for path resolution. I wonder if this is intention...
Example:

 
    handlers {

        get {
            render groovyTemplate("index.html", title: "Groovy4soapUI")
        }

        get('calculator/:operation?') {  Calculator calc ->
            calc.operate(pathTokens.operation, request.queryParams.opone, request.queryParams.optwo)
            response.send "application/json", toJson(calc)
        }


        get(':unknow?') {
            render groovyTemplate( "404.html" )
        }

        assets "public"
    }
 

and this:
 
     handlers {

        get(':unknow?') {
            render groovyTemplate( "404.html" )
        }
        
        get {
            render groovyTemplate("index.html", title: "Groovy4soapUI")
        }

        get('calculator/:operation?') {  Calculator calc ->
            calc.operate(pathTokens.operation, request.queryParams.opone, request.queryParams.optwo)
            response.send "application/json", toJson(calc)
        }

        assets "public"
    }
   

Idea behind unknow handler to return my 404 page. But how I made it ( also wonder is this correct ) if unknow is declared first you can not access index.html with http://localhost:5050 or http://localhost:5050/ this tells me that order is important. If this is correct is there an explicit way to order handlers so I can avoid ambiguous paths.

2. Is there a way to access handler registry so I can create chains on fly? For example if I have three handlers like above and use path like this:
http://localhost:5050/calculator.xml/plus?opone=1&optwo=2

or

http://localhost:5050/calculator/plus?opone=1&optwo=2&type=xml
I want to render response as xml, but if :
http://localhost:5050/calculator.json/plus?opone=1&optwo=2

or

http://localhost:5050/calculator/plus?opone=1&optwo=2&type=json

I want to render response as JSON. I do not want to have same code in each of my handlers. I guess this could be achieved by new creating chains from declared ones. So when handlers: get, get(':unknow?') and get('calculator/:operation?') are loaded for each of them new chain is created appending new handler ( responsible for rendering response ). This way I would not have to call it explicitly..

Is this possible with groovy app?

Hope I'm clear enough..

\\robert
Reply | Threaded
Open this post in threaded view
|

Re: Few questions about handlers...

Luke Daley
Administrator
> 1. Order of handlers do matter for path resolution. I wonder if this is intention...

Order is crucially important, and this is very much intentional.

If you want a 404 handler, you should do this:

handlers {
  // app handlers
 
  assets("public") {
    render groovyTemplate( "404.html" )
  }
}

That version of assets() invokes the closure handler if it can't find a file to serve.

A better solution would be to register a ClientErrorHandler: http://www.ratpack-framework.org/manual/current/api/org/ratpackframework/error/ClientErrorHandler.html

This would look like…

import org.ratpackframework.error.ClientErrorHandler
import org.ratpackframework.handling.Context

ratpack {
  modules {
    bind ClientErrorHandler, new ClientErrorHandler() {
      void error(Context context, int statusCode) {
        if (statusCode == 404) {
          context.render groovyTemplate("404.html")
        } else {
          context.render groovyTemplate("otherClientError.html", code: statusCode)
        }
      }
    }
  }

  handlers {
    // …
  }
}

The client error handler will be invoked if the request processing gets to the end of the chain and nothing has processed it.

> 2. Is there a way to access handler registry so I can create chains on fly? For example if I have three handlers like above and use path like this:
> http://localhost:5050/calculator.xml/plus?opone=1&optwo=2
>
> or
>
> http://localhost:5050/calculator/plus?opone=1&optwo=2&type=xml
>
> I want to render response as xml, but if :
> http://localhost:5050/calculator.json/plus?opone=1&optwo=2
>
> or
>
> http://localhost:5050/calculator/plus?opone=1&optwo=2&type=json

I'd do this like this…

get(":calculator/plus") {
    def calculatorToken = pathTokens.calculator
    if (calculatorToken !=~ /calculator\.?/) {
      // this isn't for us, let the next guy get it
      next()
      return
    }
   
    def type
   
    def calculatorSplit = calculatorToken.split("\\.", 2)
    if (calculatorSplit.size() == 1) {
      type = request.queryParams.type            
    } else {
      type = calculatorSplit[1]
    }
   
    // …
  }
}


> I want to render response as JSON. Is this possible with groovy app?

You can use Groovy's built in JSON support.

See: https://github.com/robfletcher/midcentury-ipsum/blob/master/src/ratpack/ratpack.groovy#L25

Reply | Threaded
Open this post in threaded view
|

Re: Few questions about handlers...

robert
Hello,

Thanks. Your error handling is much better.

On the other hand I wanted to avoid solution with parsing path. I wanted something like:

 modules {
    register new PreAllHandlers()
    register new PostAllHandlers()
 }
 handlers {
    get("something") {
     ....
    }

    get("some2") {
     ...
    }
 }

Where PreAllHandlers will execute before chain starts and PostAllHandlers when chain ends. I was looking trough docs and examples you listed and come with solution like this:

handlers {
    
    handler {
      //this is first handler in any chain
      //do something smart here
     next()
    }

    get("something") {
     ....
    }

    get("some2") {
     ...
    }
    ....
    get("someN") {
      ...
    }
     handler {
      // this is last handler in any chain if any handler before did not send response or client error
      // or finished chain in some way
      // format message and send it back
    }
 }

You can see full code here: https://github.com/robert-nemet/playground/blob/master/src/ratpack/ratpack.groovy

What do you think? Would be this valid solution? As you can see I hacked a request path to achieve what I wanted.

\\robert