Customized Grails Controller for REST

Update: new code https://gist.github.com/4152409

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
    }
    ...
  }

...

Flattr this!

RESTfullness and web-frameworks

After working on an offline mobile web app that integrated with a Grails backend, and after that being prompted to explore options for a new some green field development, which lead me to re-evalutate things like REST to NoSQL to MVC frameworks in general to mobile frameworks, to front-end frameworks in general. I feel like I have started to form a more robust comprehension of where web-app development is headed in general, and most of the web-frameworks I know of seem to be missing it so far. This would be hard to articulate briefly, but blogs are good for taking a wild stab at that sort of thing, right? Disclaimer: this is just me sort of thinking out loud, so take it for what it is.

I am coming to the conclusion that I don’t think I want to use Grails anymore. Either that or I want to gut it of a lot of what it does. Sitemesh, don’t need it. Hibernate, don’t really want SQL database anymore, schema’s are so restricting/un-agile, so don’t need it. GORM, dislike it about as much as I find it useful, so could really take it or leave it. if you end up working with a object DB then it is pretty much an unnecessary abstraction anyway. Groovy, well I like it better than Java, but honestly Scala seems like it might be the most promising language on the JVM, and for that matter other non-JVM languages have plenty of appeal too. Resources plugin, Tablibs (built in or customizable), Scaffolding and Templates, i18n… better handled by a front-end framework.

Or…  RESTfullness and MVC are beautifully simple things, and these plus the idea that next generation web applications can no-longer count on consistent and/or high-speed connectivity, but can count on robust javascript engines on the client side means that pushing as much of the application to the client as possible is now something to strongly consider. . Grails (and lets not just pick on Grails, most web-frameworks I know of) is still stuck in the paradigm where views are generated server-side .

Grails, again, to be fair, this seems to be a pattern for web frameworks in general, has been advancing in ways that make it more powerful and thus more complex, not less. True it does a decent job of hiding that complexity away most of the time, but even so, what if  its being there is all unnecessary in the first place? The trend in the way people are using their computers/devices would seem to me to drive rich apps working on the client-side with relatively simple storage and syncing services that they connect to. Maybe what it means for web-frameworks to evolve at this point means to specialize, simplify, and strip down.

Flattr this!

SSH tunneling in Ubuntu

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?

Flattr this!

Jan 2010 Ubuntu Browser Benchmarks

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

Flattr this!

A Service is not a Product

A recent article details How Google Is ‘Closed’, Just Like Apple

I have to disagree. They may both have aspects that are closed, but they are definitely not ‘just like’ each other. Apple sells a product that is closed, Google sells a service that is closed. The difference is crucial, and should be obvious to anyone who has taken business 101. Some companies make money on a product some on a service. A closed service is nothing new, and doesn’t offend me (though it may entrap me). A closed product is a new concept. It is offensive because it restricts me in new ways that I am not accustomed to evidenced by new laws that have to be created to enforce the restrictions. I would add that if these restrictions actually were justifiable we wouldn’t need new laws to enforce them and thus wouldn’t feel offended.

Apple has plenty of closed services as well by the way, so they may qualify as doubly closed, or maybe closed squared?

Flattr this!

my sunspider test results for Sept.

Run on Ubuntu 10.04 64bit on core2quad@2.66Ghtz

Browser Version Sunspider result
Chromium 7.0.530.0 336.0ms +/- 9.1%
Midori 0.2.8 366.4ms +/- 2.1%
Epiphany 2.30.2 454.4ms +/- 3.8%
Opera 10.62 397.8ms +/- 2.8%
Firefox 3.6.11pre 1805.0ms +/- 3.0%
Swiftfox 3.6.10 955.0ms +/- 1.3%
Firefox 4b7pre 462.6ms +/- 7.9%

Chromium is still leading the pack, but it’s lead is not as dramatic as it used to be. Firefox 4 is shaping up to be a pretty stellar browser overall. Still waiting for the UI on Linux to get some love though. Swiftfox, which is essentially Firefox optimized for specific chip architectures, is interesting. It is almost twice as fast in this benchmark compared to standard Firefox . Maybe Firefox should do this themselves if they want to eek out some extra performance, but I suppose there are reasons not to as well.

Looking back it is pretty impressive how much faster browser javascript has gotten over the last couple years.

Flattr this!

Pragmatism, Idealism, Tension and Balance

A friend and I got into a brief discussion around audio codecs and licence restrictions today as we talked about working on something together – specifically why Firefox doesn’t support mp3 in their audio tag. Other discussions we have had hit on this idea of pragmatism vs. idealism. Today I was reminded of this now-out-of-date article that still had some interesting points to make (while also making dumb points along the way).

What I gleaned from the article is that there can be a good sort of balance these perspectives can bring each other. That balance is achieved in a tension between not completely ignoring the reality of the situation, and not completely capitulating on principles that matter.
It seems to me this thought can be applied more broadly to things outside the realm of software development. Church practice, politics, family life, etc. In most things I tend to find myself farther to the side of the spectrum of “we can’t compromise on principles”. Some people I have relationships with tend to balance my perspective with their “don’t be unrealistic” perspective. There can be some tension in those relationships in the process, but I am finding myself appreciating that more than I used to. The tension can be a good thing.

Flattr this!

IP infringement and definitions

Apparently the current US administration is pushing to ‘reform’ intellectual property laws, and even some popular tech sites have chimed in. Anyone around me for any length of time over the last few years knows that intellectual property is a pet subject of mine, so I can’t help but be annoyed by what they are saying.  Is piracy theft? Well yes, but I don’t agree with what they mean. I think intellectual property is an altogether invalid concept, and even find the term ‘intellectual property’ itself objectionable because the word ‘property’ can’t legitimately be applied to ideas, patterns, or arrangements. Property by definition needs to be able to be owned in an exclusive manner. I suppose that is why they had to add the word ‘intellectual’ in front of it – to distinguish it from actual property, in which case they may as well have called it ‘imaginary property’! The argument is framed by the terms used. My aim here will to briefly question definitions. With diagrams I ‘stole’.

There is the somewhat popular graphic that emerged a while back.

In a simple way gets at a core issue. Scarce vs. non-scarce entities. 'ownership' is not violated by duplication in the way it obviously is by theft.

And lots of variations springing out of that:

pirate hater
Didn't like the original, so attempts to recast the 'pirates' as evil without really dealing with the scarcity issue. I guess the underlying claim is that piracy 'steals' the possibility to profit exclusively, and those potential profits were somehow owned by an ideas originator, however, you can't really own an opportunity any more than you can own an idea so it doesn't hold water.
Just decided pigs were more fun than stars I guess...

Some people prefer hexagons and shopping carts

A feeble attempt to appeal to the plight of the starving artist while again ignoring the core issues. Has this person lived under copyright for so long they have no ability to imagine alternative models of profitability? Do they really think without IP all creativity and innovation will cease? In general IP benefits the big guys more than the little guys. Many independent artists thrive without IP, others just prefer to do art for arts sake.
file sharing not piracy
Pulls into question the usage of the term 'piracy' with a touch of humor.

File sharing has evolved some, and I sort of feel it is worth while to illustrate how as it is actually quite relevant to the file sharing legality issue. However, I can’t really do it better than the wikipedia article on torrenting, and this demo (won’t work in IE, don’t try) does a slick job of illustrating a torrent in action.

Copying is duplication, not piracy. Piracy is theft in international waters. Theft only operates in the realm of property and ownership. Property is a scarce resource that can have exclusive ownership. Ideas can have an originators but not owners.

Flattr this!

My Android Experience Thus Far

I have had my Samsung Moment since around Thanksgiving 2009. It came with Adroid 1.5 initially and was my first smartphone. I played with it quite a bit at first, but after the first few months the novelty mostly wore off. I fell into a pattern of using it for its browser, email, twitter (mostly reading tweets not tweeting myself.) and occasionally for taking photos. Battery life was pretty dismal which actually discouraged me from using it because I would rather not have a dead phone by the afternoon.

Sometime in the spring it got updated to 2.1 which was sort of a let down to be honest. Most things were just as they were. There were a few more options as far as apps, and a nice new unlock screen, but that about covers it. standard 2.1 stuff was left out by Sprint. I guess they had their reasons.

About a month ago I decided I wanted to try to do some deeper customization. These phones are like little computers. If I could install Ubuntu on my laptop why couldn’t I do something similar on this phone.  Android is basically a Linux distro for mobile phones.

Anyway long story short – rooted it and installed custom ROM with the help of sdx-developers. I actually had some reasons for work that prompted this move, but those aren’t so relevant here. The phone is awesome again. A couple new features and capabilities come with root access that only geeks will appreciate, and all the bloatware that I never used and couldn’t get rid of was gone, but the most useful aspect is the dramatically improved battery life. Now a full day of heavy use is no problem. Two full days is pushing it a bit, but I do it from time to time. The wireless tethering is slick and actually useful when traveling. (did I mention I am not paying Sprint for this feature? … don’t tell….)

It comes with some consequences. The occasional random reboot or flickery screen, but so far they haven’t really interrupted anything I needed to do. reboot is faster than it used to be too. Overall the stability isn’t really a hit, because the phone wasn’t glitch free before anyway.

What is cool is that these now ‘old’ phones (Sprint tweeted they were done providing updates for the Moment 6-7 months after it was released!) can continue to be very useful because of an active developer/hacker community. I do encounter these longings to have the latest greatest devices, but I am also beginning to see much more challenge/fun/value in being able to keep lower end hardware useful through better software.

The more I have a smartphone the less I want to be without one. It is interesting how my computer usage habits are changing because of it. Maybe a topic for another post.

Flattr this!

week of year in jqueryUI datepicker

I needed to display week of year in a colum on the jqueryUI datepicker. Luckily it has the feature built in, unluckily it has a quirk relative to the way we typically display calendars in the US with Sunday as the first day colum. At first I thought it was a bug, but technically it is not, so I guess it is better classified as a gotcha. Anyway, to get the week of year to display as we would expect in the US you need two pieces.

First where you instantiate the datepicker:

$(".uiDatePicker").datepicker({minDate: -1, maxDate: '+10D', defaultDate: +1, hideIfNoPrevNext: true, showWeek: true, calculateWeek: myWeekCalc });

The important argument there is the ‘calculateWeek: myWeekCalc’ .

Next you need to define the custom week of year calculator, in this case ‘myWeekCalc’:

function myWeekCalc(date) {
  var checkDate = new Date(date.getTime());
  // Find Thursday of this week starting on Sunday
  checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay()));
  var time = checkDate.getTime();
  checkDate.setMonth(0); // Compare with Jan 1
  checkDate.setDate(1);
  return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
}

I borrowed this from the jqueyUI source and tweaked it to calculate the week based on the Thursday in the row instead of the first day colum in the row. To me this makes sense given the way the ISO for week of year is determined.

It seems to be working perfectly for me. Let me know if you use this and run into issues 🙂

Flattr this!