Search code examples
vapor

How to expose only some routes depending on host


I have a Vapor app that needs to do most things authenticated via HTTPS, but also needs to receive unauthenticated PUT requests via HTTP.

Can I conditionalize my route definitions based on the server's host name or authentication type? How can I capture that information from the server?


Solution

  • If you start up the different instances of vapor using the command line argument --hostname, you can put this code in your configure.swift and then include different routes as needed per host. You will then get 404s if invalid routes are attempted on the wrong hosts.

    if let index = env.arguments.index(of: "--hostname")
    {
        if env.arguments.count > index
        {
            let hostname = env.arguments[index+1]
            if hostname == "hostA"
            {
                 // load routes
            }
            else
            {
                 // load other routes
            }
        }
    }
    

    An alternative is to use custom Middleware. Something like this enables the hostname being called in the request to be inspected and prohibited routes can be re-directed:

    struct HostSpecificMiddleware:Middleware
    {
        func respond( to request: Request, chainingTo next: Responder ) throws -> Future<Response>
        {
            let host = request.http.headers.filter{ (arg) in let (name, _) = arg; return name == "Host" }[0]
            if host.1 == "hostA:8080"
            {
                if request.http.url.path == "routeA"
                {
                    throw Abort.redirect(to:"routeNotAllowed")
                }
            }
            return try next.respond(to: request)
        }
    }
    

    You can then configure the middleware into routes in configure.swift using:

    let soMW = HostSpecificMiddleware()
    let users = router.grouped(uriUsers).grouped(soMW)
    

    The second approach gives you much more flexibility.