Archive for the ‘Web development’ Category

Customized Grails Controller for REST

November 22nd, 2011

Grails can do RESTfull easily enough, but I wanted a restful API from grails without throwing out grails scaffolding, So I decided to customize Grails’ controller template.

grails install-templates

then in [app-name]/src/templates/scaffolding/Controller.groovy

import org.springframework.dao.DataIntegrityViolationException
import grails.converters.XML
import grails.converters.JSON

class ${className}Controller {

	static allowedMethods = [list:'GET',
		show:'GET',
		edit:['GET', 'POST'],
		save:'POST',
		update:['POST','PUT'],
		delete:['POST','DELETE']
	]

	def index() {
		redirect(action: "list", params: params)
	}

	def list() {
		params.max = Math.min(params.max ? params.int('max') : 50, 200)
		def list = ${className}.list(params)
		def listObject = [${propertyName}List: list, ${propertyName}Total: ${className}.count()]
		withFormat {
			html listObject
			json { render list as JSON }
			xml { render listObject as XML }
		}
	}

	def create() {
		[${propertyName}: new ${className}(params)]
	}

	def save() {
		def ${propertyName} = new ${className}(params)
		if (!${propertyName}.save(flush: true)) {
			withFormat {
				html {render(view: "create", model: [${propertyName}: ${propertyName}])}
				json {
					response.status = 403
					render ${propertyName}.errors as JSON
				}
				xml {
					response.status =403
					render ${propertyName}.errors as XML
				}
			}
			return
		}
		flash.message = message(code: 'default.created.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), ${propertyName}.id])
		withFormat {
			html {
				redirect(action: "show", id: ${propertyName}.id)
			}
			json {
				response.status = 201
				render ${propertyName} as JSON
			}
			xml {
				response.status = 201
				render ${propertyName}.id
			}
		}
	}

	def show() {
		def ${propertyName} = ${className}.get(params.id)
		if (!${propertyName}) {
			withFormat {
				html {
					flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
					redirect(action: "list")
				}
				json { response.sendError(404) }
				xml { response.sendError(404) }
			}
			return
		}
		def object = [${propertyName}: ${propertyName}]
		withFormat {
			html {object}
			json { render object as JSON }
			xml { render object as XML }
		}
	}

	def edit() {
		def ${propertyName} = ${className}.get(params.id)
		if (!${propertyName}) {
			flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
			redirect(action: "list")
			return
		}
		[${propertyName}: ${propertyName}]
	}

	def update() {
		def ${propertyName} = ${className}.get(params.id)
		if (!${propertyName}) {
			withFormat {
				html {
					flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
					redirect(action:"list")
				}
				json { response.sendError(404) }
				xml { response.sendError(404) }
			}
			return
		}

		if (params.version) {
			def version = params.version.toLong()
			if (${propertyName}.version > version) {
				${propertyName}.errors.rejectValue("version", "default.optimistic.locking.failure",
						  [message(code: '${domainClass.propertyName}.label', default: '${className}')] as Object[],
						  "Another user has updated this ${className} while you were editing")
				withFormat {
					html {render(view: "edit", model: [${propertyName}: ${propertyName}])}
					json { response.sendError(409) }
					xml { response.sendError(409) }
				}
				return
			}
		}

		${propertyName}.properties = params

		if (!${propertyName}.save(flush: true)) {
			withFormat {
				html {render(view: "edit", model: [${propertyName}: ${propertyName}])}
				json {
					response.status = 403
					render ${propertyName}.errors as JSON
				}
				xml {
					response.status = 403
					render ${propertyName}.errors as XML
				}
			}
			return
		}
		withFormat {
			html {
				flash.message = message(code: 'default.updated.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), ${propertyName}.id])
				redirect(action: "show", id: ${propertyName}.id)
			}
			json {
				response.status = 204
				render ${propertyName} as JSON
			}
			xml {
				response.status = 204
				render ''
			}
		}
	}

	def delete() {
		def ${propertyName} = ${className}.get(params.id)
		if (!${propertyName}) {
			withFormat {
				html {
					flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
					redirect(action: "list")
				}
				json { response.sendError(404) }
				xml { response.sendError(404) }
			}
			return
		}
		try {
			${propertyName}.delete(flush: true)
			withFormat {
				html {
					flash.message = message(code: 'default.deleted.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
					redirect(action: "list")
				}
				json {
					response.status = 204
					render ''
				}
				xml {
					response.status = 204
					render ''
				}
			}
		}
		catch (DataIntegrityViolationException e) {
			withFormat {
				html {
					flash.message = message(code: 'default.not.deleted.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
					redirect(action: "show", id: params.id)
				}
				json { response.sendError(500) }
				xml { response.sendError(500) }
			}
		}
	}

}

then modify your UrlMappings.groovy file to look something like this:

class UrlMappings {

	static mappings = {
		"/$controller/$action?/$id?"{
			constraints {
			// apply constraints here
			}
		}
		name api0: "/api/$controller/$id"(parseRequest:true){
			action = [GET: "show", PUT: "update", DELETE: "delete"]
			constraints {
				id(matches:/\d+/)
			}
		}

		name api1: "/api/$controller"(parseRequest:true){
			action = [GET: "list", POST: "save"]
		}
	}
}

I found the JSON Restful plugin a while after I already did most of this, so that is another way to go. Other than it having some issues in grails 2 right now it looks like a really good option, but one thing I like about my approach is that if you want to customize your API in fine detail you can do so. You can always generate individual controllers and modify them of course. Another option is registering custom marshallers. The simple example for customizing your JSON output without changing any controller code would be doing something like this in your Bootstrap.groovy

import grails.converters.JSON
class BootStrap {
  def init = {servletContext ->;
    JSON.registerObjectMarshaller(Person) {
      def returnArray = [:]
      returnArray['name'] = it.name
      returnArray['addrs'] = it.addresses
      return returnArray
    }
    ...
  }

...

SSH tunneling in Ubuntu

June 3rd, 2011

I wanted to work with a PostgreSQL DB remotely with PgAdmin, but I didn’t really want to figure out how to allow the DB to accept external connections in a secure way. Since I have SSH access this should be very doable. I have seen co-workers use putty for SSH tunneling before, and had previously used Putty on Ubuntu to copy that, but setting up my Natty workstation I figured there had to be a more native way to do it. Of course I could do tunneling straight from the command line. If I could ever remember the steps for it that approach would work great. Instead I found a tool called Gnome SSH Tunnel Manager (gSTM) and installed that from the Ubuntu repos. It is pretty straight forward to configure if you understand the concept of tunneling, which I only barely do, so I needed a little help getting set up, but after that it is dead simple.

  1. Install gSTM and start it up.
  2. Click ‘Add’ for a new tunnel bookmark, and name it.
  3. Add IP and user login for remote machine.
  4. Leave port and privatekey as default (unless you know what they are used for in which case you probably know what to put in there).
  5. In the port redirection section click ‘Add’, a new dialog will appear.
  6. Type is ‘local’.
  7. ‘Port’ is the port on your local machine you want to assign the tunnel to (I did 5666).
  8. ‘To host’ can be set to ‘localhost’.
  9. ‘To Port’ is the port used on the remote machine. default PostgreSQL is 5432.
  10. Click ‘OK’ and all the settings are done for gSTM so click ‘OK’ again to close the settings dialog.
  11. Highlight new tunnel, and click ‘Start’ – it should prompt you for the ssh password.
  12. Ta-da!
  13. Now use pgAdmin, or  another application to connect to the DB at localhost:5666 (or whatever port you set in step 7 above..).

Now I just need to make sure my tunnel is running in order to have access to the DB locally. Very cool! Probably where I got most confused was with the ‘To host’ and ‘To port’ settings, the wording seems backwards. Is that just me?

Jan 2010 Ubuntu Browser Benchmarks

January 17th, 2011

A follow-up of this.

Note: I am just comparing Javascript. This is no longer a good way to benchmark a whole browser, if it ever was… but it is just interesting to me, and gives one metric that is an important one.

Environment is Ubuntu 10.10 64bit on Core2Quad@2.66Ghz

Browser Version Sunspider result
Chromium 10.0.634.0 277.2ms +/- 1.8%
Midori 0.2.9 388.5ms +/- 1.0%
Epiphany 2.30.2 382.0ms +/- 2.4%
Opera 11.00 352.6ms +/- 1.8%
Firefox 3.6.14pre 1883.8ms +/- 2.6%
Swiftfox 3.6.12 1068.2ms +/- 2.3%
Firefox 4b10pre 283.6ms +/- 5.0%

All the browsers have advanced pretty well. Once Firefox 4 finally ships I’d say the playing field is pretty level for javascript performance in browsers on Linux. In real world usage I just don’t know that anyone would be able to distinguish a speed difference between the browsers when it comes to javascript. The next pieces browsers need to keep working on are HTML5 and CSS3 implementations, Hardware acceleration for 2D and 3D rendering, and additional browser features, like extensibility and ‘installable’ web apps.

As a web developer I am excited about where things are going, and how the web as a platform is advancing. Native (meaning native to the OS/Desktop environment) applications aren’t gone yet, and probably won’t be for a long time yet, but they are needing a better and better excuse to not move into the browser. What would be the benefit of that you ask? The same that Java Swing, Adobe AIR and others have tried to achieve. OS independence. You write it for Firefox according to defined standards and it should work on all browsers that implement the same standards on all the OS’s. That is a big deal! I think a couple prime candidates for proof of concept browser apps would be all the little games normally included in Ubuntu. Mines, Solitaire, Tetris clones etc. and maybe the social networking client like Gwibber. If only I had more time to play…

Update: I played some with Tetris in a browser idea

Ubuntu Lucid = mega cool, but…

April 27th, 2010

I am really enjoying the latest Ubuntu. They added lots of polish, and the OS is consistently moving steps ahead as far as ease of use for geeks and non-geeks alike. My thoughts center around, “but does it even matter?”. Sure, Ubuntu is free on a couple levels that OS X and Windows aren’t, but most non-developers don’t feel the shackles, so they don’t care.

Like an invisible tax the cost of the OS is bundled with the hardware for the vast majority. Again, for non-developers, the licence restrictions are slightly annoying at worst, also they are accustomed to paying for software, so they think “who cares?”. It would take something more significant than a very usable and free alternative OS that they would have to take the effort to install and get accustomed to make them care. I won’t be wasting a lot of breath trying to convince these sorts of users to make the switch. My lengthy discourses on open source ideology would merely prove to be confusing or annoying. That is not a guess, it’s happened.

Developers, however, have much less of an excuse for not caring. They should be feeling, or at least be aware of, the shackles of the closed environments and ecosystems. Those with a choice, often choose to ignore or to justify. I have noticed they justify their use of OSX or Windows for what tend to be short sighted reasons. If such short sighted excuses were ever really valid, is another debate, but either way, those justifications are getting weaker and weaker. Ubuntu, from a developers perspective, has potentially crossed over from being a viable alternative to being a superior one. 10.04 = a better chance of them actually being convinced, like me, that Ububtu is mega cool!

Grails active page navigation menu

March 26th, 2010

A Common feature found in many CMS’s or web-apps is a navigation menu with a highlighted active page, or the parent of the current page in a hierarchy. The trick is getting the proper element with an added CSS class of ‘selected’ or ‘active’. There are a number of ways to do this, but I just found a new way to do it in Grails using a Sitemesh’s pageProperty.

In my main layout gsp I have the nav menu


then in the head section of a view gsp’s where I want the appropriate element to have a ‘selected’ or ‘active’ class. I include:


Then in the css have something to deal with the applied class:

  #mainMenu li > a.selected { .... }

Pretty simple! I don’t know if this is very efficient in terms of performance. I can think of other ways to do this with Javascript, or params passed from the controller, but I wanted to find something that used Sitemesh as that seemed like the component that ought to handle this sort of feature. So while this is working for me, and gives a pretty good level of control, I am still wondering if it is really the ‘right’ way to do it.

For a more comprehensive explanation of Sitemesh in Grails visit this blog.