URL Routing

In a web application, routing is the process of using URLs to drive the user interface (UI). URLs are a prominent feature in every web browser, and have several main functions:

  • Bookmarking - Users can bookmark URLs in their web browser to save content they want to come back to later.
  • Sharing - Users can share content with others by sending a link to a certain page.
  • Navigation - URLs are used to drive the web browser’s back/forward functions.

Traditionally, visiting a different URL within the same website would cause a new page to be downloaded from the server, but current state-of-the-art websites are able to modify the page in response to URL changes without a full refresh.

With Kweb’s routing mechanism you get this automatically.

A simple example

import io.kweb.Kweb
import io.kweb.dom.element.new
import io.kweb.dom.element.creation.tags.h1
import io.kweb.routing.route

fun main() {
    Kweb(port = 16097) {
        doc.body.new {
            route {
                path("/users/{userId}") { params ->
                    val userId = params.getValue("userId")
                    h1().text(userId.map { "User id: $it" })
                }
                path("/lists/{listId}") { params ->
                    val listId = params.getValue("listId")
                    h1().text(listId.map { "List id: $it" })
                }
            }
        }
    }
}

Now, if you visit http://localhost:16097/users/997, you will see:

<h1>User id: 997</h1>

You can have as many path()s as you need, each with it’s own path definition. The definition can contain parameters wrapped in {braces}.

The value of these parameters can then be retrieved from the params map, but note that the values are wrapped in a KVar<String> object. This means that you can use all of Kweb’s state management features to render parts of the DOM using this value.

The key advantage here is that if the URL changes the page can be updated without a full page refresh, but rather only changing the parts of the DOM that need to change - this is much faster and more efficient.

Handing 404s

You can override the default 404 Page Not Found message in the event that none of the routes match, making it easy to integrate the 404 page with the style of your overall website:

route {
    path("/users/{userId}") { params ->
        // ...
    }
    notFound {
      h1().text("Page not found!")
    }
}

Modifying the URL

You can obtain and modify the URL of the current page using url(simpleUrlParser) within the Kweb {block}. This returns a KVar<URL > which you can use to read and modify the page URL:

import io.kweb.Kweb
import io.kweb.dom.element.creation.tags.a
import io.kweb.dom.element.new
import io.kweb.routing.route
import io.kweb.state.*

fun main() {
    Kweb(port = 16097) {
        doc.body.new {
            val path = url(simpleUrlParser).path
            route {
                path("/") {
                    path.value = "/number/1"
                }
                path("/number/{num}") { params ->
                    val num = params.getValue("num").toInt()
                    a().text(num.map {"Number $it"}).on.click {
                        path.value = "/number/${num.value + 1}"
                    }
                }
            }
        }
    }
}

If you visit http://localhost:16097/ the URL will immediately update to http://localhost:16097/number/1 without a page refresh, and you’ll see a hyperlink with text “Number 1”. If you click on this link you’ll see that the number increments (both in the URL and in the link text), also without a page refresh.

An even more elegant approach that would also work would be to replace:

path.value = "/number/${num.value + 1}"

…with…

num.value++

This would have the exact same effect because the KVars always work bidirectionally, so can be used both to read and modify that part of the page URL, resulting in an automatic re-render of the necessary DOM elements.