Question

I'm trying to build a Snap server that routes to other Snaplets depending on the Server Name in the request object. I have this so far:

makeSnaplet "name-routing" "Server name routing" Nothing $ do
    a <- embedSnaplet "first" first First.app
    b <- embedSnaplet "second" second Second.app
    wrapSite nameRoute
    return $ App a b

This gets me most of the way, but I need a mechanism for nameRoute that translates rqServerName to one of the paths that the embedded Snaplets are hosted at. Is there a way to adjust the routing to a new path without actually affecting the path information?

If not, what would be the correct way to go about embedding these Snaplets?

Was it helpful?

Solution

The snaplet system is designed to hang each snaplet's routes on a particular route prefix. This route prefix is specified in the first argument to nestSnaplet/embedSnaplet. Under the hood, the snaplet system uses the route function from snap-core to get O(log n) performance for your routing. The problem is that what you are trying to do is fundamentally incompatible with this design. I can think of two potential workarounds.

The first is to hang both of your snaplets on the same path. This will cause the two snaplets' handlers to be combined using alternative (i.e. firstHandler <|> secondHandler). Then, in the first snaplet's handler, check rqServerName. If the server name is the one you want for the first snaplet, then continue as normal. If the server name is not the one you want, then call pass. The pass function causes execution to proceed to the next alternative, namely secondHandler. If you only have two snaplets, then you're done. If you're choosing between more than two snaplets, then you need to do the same thing in secondHandler. This is similar to the way the dir function is implemented. You can see there that the pathWith function calls pass if the path doesn't match.

The downside to this approach is that you don't get log-time routing of these two snaplets. That should be fine if you only have a small number of them. But if you were choosing between a large number of snaplets this way, it would be slower.

The second approach is to not use the snaplet routing system. Just make your snaplets expose a single Handler containing all of its routes. Then you can write your own routing function that uses the server name. If you need to have log(n) routing, then you'll have to roll your own using some kind of a tree. You can look at the source code to Snap's route function for an example of how that can be done.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top