5 URL-Based Dispatch
The library allows the creation of two-way mappings between permanent URLs and request-handling procedures.
This library was inspired by the (planet untyped/dispatch) package.
Suppose you are writing a blog application and want pretty URLs for different views of the site.
You would define some URL dispatching rules as follows:
And define your request handlers as follows:
> (define (list-posts req) `(list-posts)) |
> (define (review-post req p) `(review-post ,p)) |
> (define (review-archive req y m) `(review-archive ,y ,m)) |
Now when a request is sent to your application, it will be directed to the appropriate handler:
|
> (blog-dispatch | (url->request "http://www.chrlsnchrg.com")) |
|
'(list-posts) |
> (blog-dispatch | (url->request "http://www.chrlsnchrg.com/")) |
|
'(list-posts) |
> (blog-dispatch | (url->request | "http://www.chrlsnchrg.com/posts/Extracurricular-Activity")) |
|
'(review-post "Extracurricular-Activity") |
> (blog-dispatch | (url->request "http://www.chrlsnchrg.com/archive/1984/10")) |
|
'(review-archive 1984 10) |
> (blog-dispatch | (url->request "http://www.chrlsnchrg.com/contact")) |
|
'(list-posts) |
You can also generate these pretty URLs from procedure calls:
> (blog-url list-posts) |
"/" |
> (blog-url review-post "Another-Saturday-Night") |
"/posts/Another-Saturday-Night" |
> (blog-url review-archive 1984 11) |
"/archive/1984/11" |
After mastering the world of blogging software, you decide to put the ubiquitous Add-Two-Numbers.com out of business with Sum.com:
|
|
> (sum-dispatch (url->request "http://www.sum.com/")) |
0 |
> (sum-dispatch (url->request "http://www.sum.com/2")) |
2 |
> (sum-dispatch (url->request "http://www.sum.com/2/3/4")) |
9 |
> (sum-dispatch (url->request "http://www.sum.com/5/10/15/20")) |
50 |
> (sum-url sum empty) |
"/" |
> (sum-url sum (list 1)) |
"/1" |
> (sum-url sum (list 2 3 5 7)) |
"/2/3/5/7" |
5.2 API Reference
Returns two values: the first is a dispatching function with the contract
(-> request? any)
that calls the appropriate
dispatch-fun based on the first
dispatch-pattern that matches the
request’s URL; the second is a URL-generating function with the contract
(-> procedure? any/c ... string?)
that generates a URL using
dispatch-pattern for the
dispatch-fun given as its first argument.
If else-fun is left out, one is provided that calls (next-dispatcher) to signal to the Web Server that this
dispatcher does not apply.
dispatch-pattern | | = | | () |
| | | | | (string . dispatch-pattern) |
| | | | | (bidi-match-expander ... . dispatch-pattern) |
| | | | | (bidi-match-expander . dispatch-pattern) |
Like
dispatch-rules, except returns a third value with the contract
(-> request? boolean?) that returns
#t if the dispatching rules apply to the request and
#f otherwise.
Calls
serve/servlet with a
#:servlet-regexp argument (
#rx"") so that every request is handled by
dispatch.
5.3 Imperative Dispatch Containers
dispatch-rules is purely functional. This presents a more declarative interface, but inhibits some programming and modularity patterns. Containers provide an imperative overlay atop dispatch-rules.
Defines container-id as a container as well as dispatch-id as its dispatching function and url-id as its URL lookup function.
Like
dispatch-rules, but imperatively adds the patterns to the container specified by
container-expr. The new rules are consulted
before any rules already in the container.
5.4 Built-in URL patterns
web-server/dispatch builds in a few useful URL component patterns.
You can create new URL component patterns by defining bi-directional match expanders.
Binds
id to a
bi-directional match expander
where
in-xform is a match expander (defined by
define-match-expander) that is used when parsing URLs
and
out-xform is one used when generating URLs.
Both in-xform and out-xform should use the syntax (xform arg ... id) where the args are
specific to id and compatible with both in-xform and out-xform. id will typically be provided
automatically by dispatch-rules.
When defining new patterns, you may find it useful to use these helper functions:
Binds id to a match expander that expands (id x) to
(? test? (app coerce x)) (i.e., uses test? to determine if the pattern matches and coerce to transform the binding.)
Returns a function that returns #t if coerce would not throw an exception or return #f on its input.
Examples: |
> (define string->number? (make-coerce-safe? string->number)) |
> (string->number? "1") |
#t |
> (string->number? "1.2") |
#t |
> (string->number? "+inf.0") |
#t |
> (string->number? "one") |
#f |