[racket] passing a list of dispatch clauses to dispatch-rules

From: Jay McCarthy (jay.mccarthy at gmail.com)
Date: Wed Dec 18 04:56:21 EST 2013

There's an annoying terminological problem.

The core Web server has a concept of a dispatcher sequence and
(next-dispatcher) jumps to the next of those. The web-server/dispatch
library helps you write a function that does pattern matching on the
URL of a request. What you want is that after you take a branch in
that function, you'd like to have the branch fail and then the pattern
matching try again.

racket/match [which web-server/dispatch is built on] supports
something like that:

(define (a in)
  (match in
    [x
     (define y (string->number x))
     (if y
       y
       (failure-cont))]
    ["home"
     "It's home!"]
    [_
     "Unknown"]))

(module+ test
  (require rackunit)
  (check-equal? (a "4") 4)
  (check-equal? (a "home") "It's home!")
  (check-equal? (a "five") "Unknown"))

But the use of (failure-cont) has to be syntactically within the
match, i.e. the following does not work:

(define (b-helper x)
  (define y (string->number x))
  (if y
    y
    (failure-cont)))

(define (b in)
  (match in
    [x
     (b-helper y)]
    ["home"
     "It's home!"]
    [_
     "Unknown"]))

If you really need to sequence them this way, then you could use

1. serve/launch/wait
2. sequence dispatcher
3. dispatch/servlet handling files
4. and then dispatch/servlet handling everything else

So that the (next-dispatcher) in step 3 jumped to step 4.

Jay


On Tue, Dec 17, 2013 at 1:23 PM, Janos Tobias Locsei
<jtlocsei at cantab.net> wrote:
> Just realized I can the desired behavior by just putting the (string-arg) as
> the last clause:
>
> (define-values (url-based-dispatch url-generator)
>   (dispatch-rules
>
>    [("home") display-home]
>    [("some-app") run-app]
>    [((string-arg)) dispatch-static-html]))
>
> I'm still curious though whether it's possible to skip to the next clause by
> calling next-dispatcher within one dispatch function. The discussion at
> http://lists.racket-lang.org/users/archive/2013-September/059728.html
> made me think this was possible. In that example, I thought that when
> "funny-fish.png" is matched and fail-to-fs throws next-dispatcher that the
> idea was for the program to keep trying with the rest of the clauses in the
> dispatch rules.
>
> Tobias
>
>
> On 17 December 2013 17:25, Janos Tobias Locsei <jtlocsei at cantab.net> wrote:
>>
>> Hi Jay, I tried again using serve/servelet. This is my full code:
>>
>> #lang racket
>>
>> (require web-server/dispatch ; for dispatch-rules
>>          web-server/dispatchers/dispatch ; for next-dispatcher
>>          web-server/servlet-env ; for serve/servlet
>>          web-server/http ; for response/xexpr
>>          )
>>
>> (define-values (url-based-dispatch url-generator)
>>   (dispatch-rules
>>    [((string-arg)) dispatch-static-html]
>>    [("home") display-home]
>>    [("some-app") run-app]))
>>
>> (define (dispatch-static-html request a-path-string)
>>   (display "Entered dispatch-static-html\n")
>>   ; This will eventually have code to search for static html
>>   ; files and display them. For now, just pretend we couldn't find
>>   ; the relevant html file so we throw next-dispatcher.
>>   (next-dispatcher))
>>
>> (define (display-home request)
>>   (display "Entered display-home\n")
>>   (response/xexpr
>>    `(html
>>      (head (title "Home"))
>>      (body (h1 "Home")
>>            (p "Welcome to the home page")))))
>>
>> (define (run-app request)
>>   (display "Entered run-app\n")
>>   (response/xexpr
>>    `(html
>>      (head (title "App"))
>>      (body (h1 "App")
>>            (p "This app is actually just a static page")))))
>>
>>
>> (define (respond-unknown request)
>>   (display "Entered respond-unknown\n")
>>   (response/xexpr
>>    `(html
>>      (head (title "Unknown Reponse"))
>>      (body (h1 "Unknown Response")
>>            (p "Sorry, I couldn't find what you're looking for")))))
>>
>> (serve/servlet
>>  url-based-dispatch ; answers requests
>>  #:servlet-path "/home" ; default url
>>  #:servlet-regexp #rx"" ; capture all top-level requests
>>  #:file-not-found-responder respond-unknown)
>>
>> What I was expecting (and wanting) was that for the URL
>> "http://localhost:8000/home" the function dispatch-static-html would be
>> called (because it matches any URL), it would throw next-dispatcher, and
>> then display-home would be called, since it's the next matching clause.
>>
>> But in reality when dispatch-static-html throws next-dispatcher the
>> program jumps straight to respond-unknown, which I specified as the
>> file-not-found-responder keyword argument when I called serve/servlet.
>>
>> What am I missing? Is there a way to get the program to do what I wanted
>> it to?
>>
>> Thanks for all your time with this.
>>
>> Tobias
>>
>>
>>
>>
>> -------------------------------
>>
>>
>> Thanks Jay, that makes sense. I was testing it without using
>> serve/servlet, using the example on
>> http://docs.racket-lang.org/web-server/dispatch.html
>>
>> I will try again using serve/servlet.
>>
>>
>> On 17 December 2013 14:45, Jay McCarthy <jay.mccarthy at gmail.com> wrote:
>>>
>>> The first one is what I would write, except that I'd put it after the
>>> ["" ...] case so it doesn't shadow it.
>>>
>>> How are you testing this code? (next-dispatcher) is supposed to throw
>>> an exception, but it will caught and used by the Web server when you
>>> are using serve/servlet, etc.
>>>
>>> Jay
>>>
>>> On Tue, Dec 17, 2013 at 7:11 AM, Janos Tobias Locsei
>>> <jtlocsei at cantab.net> wrote:
>>> > I thought I'd add a note about what my overall objective with this is,
>>> > in
>>> > case there's a completely different way of achieving the same thing.
>>> >
>>> > Basically what I want is to be able to serve a combination of apps and
>>> > static html pages on my domain, but I don't want ".html" as the end of
>>> > the
>>> > url for the static pages. So, if someone goes to the url
>>> >
>>> > http://mysite.com/lolcats
>>> >
>>> > ...then I'd like the web server will look in the directory
>>> > /htdocs/static-html/ and check whether there's a file called
>>> > lolcats.html,
>>> > and serve that page if it's there.
>>> >
>>> > My idea was that to achieve this I'd write a dispatch function that
>>> > would
>>> > check the static-html directory for a file with the correct name, and
>>> > serve
>>> > that page using the "include-template" function in
>>> > web-server/templates.
>>> >
>>> > But if there's an easier/better way of achieving the same thing then
>>> > I'm
>>> > open to that.
>>> >
>>> > Tobias
>>> >
>>> >
>>> >
>>>
>>>
>>>
>>> --
>>> Jay McCarthy <jay at cs.byu.edu>
>>> Assistant Professor / Brigham Young University
>>> http://faculty.cs.byu.edu/~jay
>>>
>>> "The glory of God is Intelligence" - D&C 93
>>
>>
>



-- 
Jay McCarthy <jay at cs.byu.edu>
Assistant Professor / Brigham Young University
http://faculty.cs.byu.edu/~jay

"The glory of God is Intelligence" - D&C 93

Posted on the users mailing list.