Permalink
Browse files

allow custom 500 and 404 handlers

  • Loading branch information...
1 parent 5003042 commit 44b4097c7e68ed192555f5498b137da087431a54 @dantebronto committed Jan 24, 2011
Showing with 78 additions and 15 deletions.
  1. +23 −2 examples/misc/app.js
  2. +2 −0 lib/picard/index.js
  3. +18 −10 lib/picard/request.js
  4. +1 −1 lib/picard/routing.js
  5. +12 −2 lib/picard/server.js
  6. +22 −0 spec/misc/misc_spec.js
View
25 examples/misc/app.js
@@ -3,6 +3,23 @@ require('../../lib/picard').
// Many top-level functions return 'this', allowing
// for chaining of routes without calling Picard.globalize()
+error(function(ex){ // custom error handler, takes an exception arg
+ this.onScreen({
+ status: 500,
+ body: '<h1> Custom 500 Error! </h1>' +
+ '<h3>' + ex.message + '</h3>' +
+ '<pre>' + ex.stack + '</pre>'
+ })
+ require('sys').puts(ex.stack)
+}).
+
+notFound(function(){ // custom 404 action
+ this.onScreen({
+ status: 404,
+ body: '<h1> Custom 404! </h1>'
+ })
+}).
+
// process a posted form
post('/with_params', function(params){
return { text: '<h1>' + params.foo + ' ' + params.baz + '</h1>' }
@@ -34,12 +51,16 @@ get('/returns_triplet', function(){
return [201, headers, 'this is the response']
}).
-get('/passing/:blah', function(env){
- env.pass() // pass to the next matching route handler
+get('/passing/:blah', function(env){ // pass to the next matching route handler
+ env.pass() // don't return if passing
}).
get('/passing/to_me', function(){
return 'passed from previous route'
}).
+get('/throws/error', function(){
+ return foo.bar // not defined
+}).
+
start()
View
2 lib/picard/index.js
@@ -3,6 +3,8 @@ var Picard = {
set: require('./config').set,
version: require('./server').version,
start: require('./server').start,
+ error: require('./server').error,
+ notFound: require('./server').notFound,
template: require('./template').template
}
View
28 lib/picard/request.js
@@ -16,7 +16,7 @@ var RequestExtensions = {
this.cookies[name] = options
},
- handleException: function(ex) {
+ handleException: function(ex){
this.onScreen({
status: 500,
body: '<h1> 500 Error </h1>' +
@@ -25,25 +25,33 @@ var RequestExtensions = {
})
sys.puts(ex.stack)
},
+ handleNotFound: function(){
+ this.onScreen({
+ status: 404,
+ body: '<h1> 404 Not Found </h1>'
+ })
+ },
onScreen: function(scope){
var req = this,
type = toString.call(scope)
- if( req.response.finished ) return
+ if ( req.response.finished ) return
- if ( scope == null )
- scope = { status: 404, body: "<h1> 404 Not Found </h1>" }
- else if ( type == '[object String]' )
+ if ( type == '[object String]' )
scope = { text: scope }
else if ( type == '[object Array]' )
scope = { status: scope[0], headers: scope[1], body: scope[2] }
+ else if ( scope == null ){
+ req.handleNotFound()
+ return
+ }
scope.status = scope.status || 200
scope.headers = scope.headers || []
scope.body = scope.text || scope.body || ''
scope.encoding = scope.encoding || 'utf8'
- if (scope.headers.length == 0 ){
+ if ( scope.headers.length == 0 ){
scope.headers.push([ 'Server', req.picardServer || 'Picard ' + server.version ])
scope.headers.push([ 'Content-Type', scope.type || 'text/html' ])
}
@@ -77,7 +85,7 @@ var RequestExtensions = {
}
},
sendData: function(scope){
- if( !scope.body ) return
+ if ( !scope.body ) return
scope.headers.push([ 'Content-Length', scope.body.length ])
scope.headers.push([ 'Content-Encoding', scope.encoding ])
this.response.writeHead(scope.status, scope.headers)
@@ -86,7 +94,7 @@ var RequestExtensions = {
},
extractFormParams: function(chunk){
try {
- if( chunk == undefined ) return
+ if ( chunk == undefined ) return
var chunks = chunk.toString().replace(/\+/g, '%20').split('&')
this.body = ('body' in this) ? this.body + chunk : chunk;
@@ -102,7 +110,7 @@ var RequestExtensions = {
extractRouteParams: function(route, match_data){
var i, l
- if( match_data == null ){ return } else { match_data.shift() }
+ if ( match_data == null ){ return } else { match_data.shift() }
this.captures = []
for(i=0, l = route.keys.length; i < l; i++)
@@ -116,7 +124,7 @@ var RequestExtensions = {
this.cookies = {}
var self = this
var cookieHeader = self.headers['cookie']
- if (cookieHeader){
+ if ( cookieHeader ){
cookieHeader.split("; ").forEach(function(cookie){
var parts = cookie.split("=")
self.cookie(parts[0], decodeURIComponent(parts[1]), { preset: true })
View
2 lib/picard/routing.js
@@ -20,7 +20,7 @@ var Routes = {
executeCallback: function(request){
var routesByType = Routes.byRestType(request)
var route, matches
-
+
for(var i=0, l = routesByType.length; i < l; i++){
route = routesByType[i]
matches = request.parsedUrl().pathname.match(route.path)
View
14 lib/picard/server.js
@@ -18,8 +18,18 @@ var Server = {
return this
},
+ error: function(proc){
+ http.IncomingMessage.prototype.handleException = proc
+ return this
+ },
+ notFound: function(proc){
+ http.IncomingMessage.prototype.handleNotFound = proc
+ return this
+ },
version: 'v0.3 "There are... four... lights!"'
}
-exports.start = Server.start
-exports.version = Server.version
+exports.start = Server.start
+exports.version = Server.version
+exports.error = Server.error
+exports.notFound = Server.notFound
View
22 spec/misc/misc_spec.js
@@ -86,4 +86,26 @@ describe('DELETE', function(){
asyncSpecWait()
})
+})
+
+describe('custom error and 404 handlers', function(){
+
+ it('should allow for custom 500 handlers', function(){
+ testReq('GET', '/throws/error', function(status, _, body){
+ expect(body).toMatch('<h1> Custom 500 Error! </h1><h3>foo is not defined</h3>')
+ expect(status).toEqual(500)
+ asyncSpecDone()
+ })
+ asyncSpecWait()
+ })
+
+ it('should allow for custom 404 handlers', function(){
+ testReq('GET', '/does/not/exist', function(status, _, body){
+ expect(body).toEqual('<h1> Custom 404! </h1>')
+ expect(status).toEqual(404)
+ asyncSpecDone()
+ })
+ asyncSpecWait()
+ })
+
})

0 comments on commit 44b4097

Please sign in to comment.