Router
Unnested
In order to better structure the app ambiorix comes with the ability to create routers. These allow having a base path prepended to every route subsequently added to it; thereby enabling to physically and mentally better structure the routing logic of an application.
Consider the application below which does not make use of a router.
library(ambiorix)
# core app
app <- Ambiorix$new()
# homepage
app$get("/", \(req, res){
res$send("Home!")
})
# /users logic
app$get("/users", \(req, res){
res$send("List of users")
})
app$get("/users/:id", \(req, res){
cat("Return user id:", req$params$id, "\n")
res$send(req$params$id)
})
app$get("/users/:id/profile", \(req, res){
msg <- sprintf("This is the profile of user #%s", req$params$id)
res$send(msg)
})
app$start()
Ideally the /users
logic should be separated from the main app, below we use the router in a router.R
file where we place the /users
logic. A base path is passed to the router instantiation; this will make it such that every subsequent route attached to the router will be prepended by this base path.
# router.R
# create router
router <- Router$new("/users")
router$get("/", \(req, res){
res$send("List of users")
})
router$get("/:id", \(req, res){
cat("Return user id:", req$params$id, "\n")
res$send(req$params$id)
})
router$get("/:id/profile", \(req, res){
msg <- sprintf("This is the profile of user #%s", req$params$id)
res$send(msg)
})
We can then simplify app.R
: it needs to source the router from router.R
, the router then needs to be mounted on the core application with the use
method.
library(ambiorix)
# core app
app <- Ambiorix$new()
app$get("/", \(req, res){
res$send("Home!")
})
# mount the router
app$use(router)
app$start()
Nested
To improve logical organization and reuse of middleware across your app, you sometimes need nested routers.
Nesting of routers is as easy as router1$use(router2)
. Here’s an example:
library(ambiorix)
library(htmltools)
# routers + handlers:
first_router <- Router$new("/first")
first_router$get("/", \(req, res) {
res$send(h1("Users"))
})
second_router <- Router$new("/second")
second_router$get("/", \(req, res) {
res$send(h1("Second!"))
})
third_router <- Router$new("/third")
third_router$get("/", \(req, res) {
res$send(h1("Third!"))
})
# middleware
second_middleware <- \(req, res) {
cat("Hello from /second...\n")
}
# nesting:
second_router$use(second_middleware)
second_router$use(third_router)
first_router$use(second_router)
# app instance:
app <- Ambiorix$new()
app$use(first_router)
app$get("/", \(req, res) {
page <- div(
tags$a(href = "/first", "1"),
tags$a(href = "/first/second", "2"),
tags$a(href = "/first/second/third", "3")
)
res$send(page)
})
app$start()
Once you run the app, you can visit these endpoints:
/
/first
/first/second
/first/second/third
Note how the second_middleware
runs on both /first/second
& /first/second/third
.