Posts from April 2011

Serving Images (Favicons) with Ratpack Middleware

Posted

One of the things I noticed from running the sample material was that I would get a 404 error when clients try to retrieve the favicon.ico file. I thought it would be a matter of just dropping the favicon.ico file into the app directory. If only it were that simple... What ended up working is creating a new route for the favicon and working some HttpResponse mojo to get Ratpack to serve up the image. Adding a route directly to our app file is nice but a bit messy. I split out the new route into its own file in an attempt to create a pseudo-Ratpack middleware. The file is listed below:

class Helpers {
    static addFavicon = { app ->
	def handler = {
	    try {
		response.setContentType("image/ico");
		file = new File('favicon.ico')
		response.setContentLength((int)file.length())
					
		inStream = new FileInputStream(file)
		out = response.getOutputStream();
					
		// Copy the contents of the file to the output stream
		byte[] buf = new byte[1024];
		int count = 0;
		while ((count = inStream.read(buf)) >= 0) {
		    out.write(buf, 0, count);
		}
		inStream.close();
		out.close();
	    } catch(Exception ex) {}
		""
	}

	app.get('/favicon.ico', handler)
    }
}

The empty string at the end of the handler is to make sure Ratpack doesn't balk at us handling the strream ourselves.

The code from the last post was just a closure so we need to modify it a little bit to automagically handle the favicons. Be aware that saving the file as a script in this manner(below) somewhat breaks the script from working with the ratpack script file. The reason for this is because the ratpack file expects there to only be a closure in any file you pass to it. The scaffolding we added to the file duplicates what the ratpack script was already doing so it fusses at you ... something about being DRY ;) ... but you've already deployed the libs to your .groovy so you can run it like any other groovy script making sure to pass in the Helpers.groovy file as well.

import com.bleedingwolf.ratpack.*
import groovy.ratpack.*

def app = Ratpack.app({
    get("/") {
	response.sendRedirect("/helloworld")
    }
    get("/helloworld") {
	"Hello, World!"
    }	
    get("/error/:error") {
	response.sendError(new Integer(urlparams.error))
    }	
    get("/data") {
	request.toString()
    }	
})

Helpers.addFavicon(app)
RatpackServlet.serve(app)

Alternatively, we can add the Helpers.... line to the ratpack script file. Or even yet, one might provide a gradle script and have the file be copied somewhere that is accessible to all the Ratpack apps.

Create Lightweight Groovy Web Apps with Ratpack

Posted

Besides having one of the most awesome names for a Groovy project, well besides Griffon ;), Ratpack is a nice web framework to scaffold and prototype ideas.

Inspired by the Sinatra Ruby web framework, Ratpack puts routes (URL mappings) at the forefront. Compared to Grails, it's a more bootstraped experience but is useful for small projects. Just as Sinatra coexists with Rails, Ratpack can coexist with Grails.

Route Basics

Each route contains the code that will be executed when it is accessed. Here is a basic route that prints "Hello, World!" when someone navigates to localhost:5000/helloworld:

get("/helloworld") {
    "Hello, World!"
}

Behind the scenes, there is a handler that is injecting a HttpServletRequest and HttpServletResponse for us to interact with. That means that you don't have to learn a new protocol and you can leverage your Java Servlet knowledge. To further illustrate this, any of the following routes would work as well:

get("/") {
    response.sendRedirect("/helloworld")
}
get("/error/:error") {
    response.sendError(new Integer(urlparams.error))
}
get("/data") {
    request.toString()
}

We can see from the error route that the :variableName notation gives us an equivalent to $variableName in Grails. They aren't listed here for brevity but any of the HTTP verbs can be routed to.

Running Ratpack

After downloading the package from Github at https://github.com/bleedingwolf/Ratpack, you'll need to run the gradle task 

gradle deployRatpack

This retrieves Jetty and other dependencies, compiles the framework, and drops all the libs into your .groovy/libs directory. I haven't had any problems with these libraries specifically but in the past libs in the .groovy directory have caused version conflicts, so just be aware. After you have the libs installed, you can run Ratpack in two different ways. Static mode uses a bash script named ratpack and any changes to files won't be picked up until you bounce the server.

ratpack <application file>

Dynamic mode operates similar to grails run-app in dev mode bouncing the server automatically when a file in the watched directory is changed:

groovy <RatpackDir>scripts/runapp.groovy <app file> <dir to monitor>

Drop the code from the two code snippets in a file and you're off to the races. No import files needed.

It remains to be seen if an ecosystem of middleware extensions as vibrant as Sinatra or Node.js builds around it but I'm looking forward to playing more with Ratpack.