[web-devel] Type-safe URL handling

Gregory Collins greg at gregorycollins.net
Tue Mar 16 12:51:36 EDT 2010

Michael Snoyman <michael at snoyman.com> writes:

> I think the only piece of the puzzle missing to combine these two
> together is to have mkResources output something along the lines of:
> data RoutePiece = StaticPiece String | IntPiece | StringPiece
> _validRoutes :: [[RoutePiece]]
> _validRoutes =
>   [ [StaticPiece "user"]
>   , [StaticPiece "user", StaticPiece "find", IntPiece]
>   , [StaticPiece "user", StaticPiece "name", StringPiece]
>   ]

Yes, this approach smells a lot better to me: the types are types and
the data are data. Just a brainstorm: if each handler monad were to
carry its routing table around with it, you could define something like:

    match :: ByteString
          -> (WhateverYourWebMonadIsCalled a)
          -> (WhateverYourWebMonadIsCalled a)

And write

    handler = match "/foo/:bar/#int/" $ do ...

without the template haskell quasiquotation (i.e. do the checking at
runtime.) Is it always true that compile-time link checking is
possible/desirable? All of these solutions also imply that each handler
knows where it's hung on the routing table so that it can resolve
relative URLs, etc.

IMO no matter what a link-checker should be lightweight enough that you
can refactor easily without rewriting a bunch of static tables; you
should be able to move an entire "subtree" to another place in the
routing table in O(1) time.

This rabbit hole goes pretty deep though; if you're serious about the
bondage and discipline approach you'd want to ensure that you can check
query parameters; i.e. "'/foo' takes a mandatory 'bar' integer parameter
on the queryString and an optional 'sort' parameter which must be either
'asc' or 'desc'", etc. At some point I have to wonder: is the medicine
worse than the disease?

Gregory Collins <greg at gregorycollins.net>

More information about the web-devel mailing list