Tuesday, August 11, 2009

SHP: Handling Not Found Errors

Although we can browse arbitrary shp pages now, if we type in a page that does not exist, we'll get the following error:

;; http://localhost/test/hello
call-with-input-file: cannot open input file: "c:\shp\test\hello" (The system cannot find the file specified.; errno=2)

What would be nice is if we can reroute the error to another page, say notfound.shp.

The change would require us to first test to see whether the file exists, and if it does not, we load the not found page instead (we'll hardcode the notfound path to notfound.shp for now):


(define (url->shp-path url path)
(define (helper script)
(if (file-exists? script) script
;; it's the developer's responsibility to ensure notfound.shp exists!!
(build-path path "notfound.shp")))
(helper (apply build-path path (url->path-segments url))))


You'll of course have to create a notfound.shp in the root path for now.

There is one additional case - if the path resolves to a directory (but without the trailing slash), we want it to resolve to the index.shp by default.

(define (url->shp-path url path)
(define (helper script)
(cond ((file-exists? script) script)
((directory-exists? script)
(helper (build-path script "index.shp")))
(else
;; it's the developer's responsibility to ensure notfound.shp exists!!
(build-path path "notfound.shp"))))
(helper (apply build-path path (url->path-segments url))))


Removing the Hardcodings

Now that we have two additional hardcoded values that should become configuration values we'll remove the hardcoding but provide defaults through optional parameters:

(define (url->shp-path url path (default "index.shp") (not-found "notfound.shp"))
(define (helper script)
(cond ((file-exists? script) script)
((directory-exists? script)
(helper (build-path script default)))
(else
;; it's the developer's responsibility to ensure notfound.shp exists!!
(build-path path not-found))))
(helper (apply build-path path (url->path-segments url))))

(define (make-shp-handler path #:default (default "index.shp")
#:not-found (not-found "notfound.shp"))
(lambda (request)
(let ((terms (file->values (url->shp-path (request-uri request) path default not-found))))
(let ((proc (eval `(lambda (request) . ,terms))))
(proc request))
)))


The trouble with optional args is that they will permeate through the calling stack, and as you add more you'll have more touch points, so in the future we'll use a configuration object instead, but for now this works.

No comments:

Post a Comment