-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: nested routers initial pass #73
Conversation
this is really great! devtools::load_all()
mdd <- \(req, res) {
print("inside a middleware")
forward()
}
home_get <- \(req, res) {
res$send("Ambiorix")
}
Ambiorix$
new(port = 8000L)$
use(mdd)$
get("/", home_get)$
start() this is the error i get on the console: ℹ Loading ambiorix
Error in super$get_middleware() : object 'router' not found
Calls: <Anonymous> -> <Anonymous>
Execution halted hint: looks like there are two small bugs... for(receiver in private$.receivers) {
receivers <- router$get_receivers(receivers)
} for(middleware in private$.middleware) {
middlewares <- router$get_middleware(middlewares)
} |
Right, now we're good. library(htmltools)
library(ambiorix)
app <- Ambiorix$new()
# routers
first_router <- Router$new("/first")
second_router <- Router$new("/second")
third_router <- Router$new("/third")
# middleware
second_middleware <- \(req, res) {
cat("Hello from /second...\n")
}
# nest
second_router$use(second_middleware)
second_router$use(third_router)
first_router$use(second_router)
app$use(first_router)
first_router$get("/", \(req, res) {
res$send(h1("Users"))
})
second_router$get("/", \(req, res) {
res$send(h1("Second!"))
})
third_router$get("/", \(req, res) {
res$send(h1("Third!"))
})
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() |
That't cool. One question, should we add an issue for adding route helpers similarly like ruby and rails routers have with support for nested routes? For example, in the case of resources :photos: photos_path returns /photos new_photo_path returns /photos/new edit_photo_path(:id) returns /photos/:id/edit (for instance, edit_photo_path(10) returns /photos/10/edit) photo_path(:id) returns /photos/:id (for instance, photo_path(10) returns /photos/10) How could be for profile paths? |
@JohnCoene good progress, the nesting is now working well. but... if we have a middleware set for the second router, it should not run when endpoints of the first router are accessed.
here's the console output: ℹ 10-10-2024 10:17:24 GET on /
Hello from /second...
ℹ 10-10-2024 10:17:45 GET on /first
Hello from /second...
ℹ 10-10-2024 10:18:39 GET on /first/second |
@kennedymwavu I'll check it should indeed not work like that but I was sure I got this right, I don't remember seeing that, I probably did something wrong. @jrosell we support parameters in ambiorix so you can totally do that, I'll share an example, unless I misunderstand your question. |
I fixed it, though it breaks all the tests... (it seems to be an issue with testthat to be honest, I'm getting some strange error). And here's an example + for @jrosell using the parameters, try app <- Ambiorix$new()
# routers
first_router <- Router$new("/first")
second_router <- Router$new("/second")
third_router <- Router$new("/third")
fourth_router <- Router$new("/fourth")
# middleware
second_middleware <- \(req, res) {
cat("Hello from /second...\n")
}
# middleware
second_router$use(second_middleware)
# routers
third_router$use(fourth_router)
second_router$use(third_router)
first_router$use(second_router)
app$use(first_router)
first_router$get("/", \(req, res) {
res$send(h1("First"))
})
second_router$get("/", \(req, res) {
res$send(h1("Second!"))
})
third_router$get("/", \(req, res) {
res$send(h1("Third!"))
})
fourth_router$get("/", \(req, res) {
res$send(h1("fourth"))
})
fourth_router$get("/:this", \(req, res) {
res$send(h1("path:", req$params$this))
})
app$get("/", \(req, res) {
page <- div(
tags$a(href = "/first", "1"),
tags$a(href = "/first/second", "2"),
tags$a(href = "/first/second/third", "3"),
tags$a(href = "/first/second/third/fourth", "4")
)
res$send(page)
})
app$start() |
Sorry for not explaining it well. I'm talking about some path helper like: For example some get_path(second_router) returning "/first/second" so it can be used in the links. |
Ah I get it! I don't think you explained it poorly, I work on OSS in the wee hours of the night so I tend to misread. We could totally consider that, I haven't explored rails but have only heard good things and DHH surely makes me want to try, I should take a look at rails to see if there are ideas/features we could port to Ambiorix. I'm just wondering where you use those helpers in your code? Would you have an example or pseudo code for me to understand? |
For unnested routers, could be:
Then you could have Why is that useful? When you nest the routers, you don't have to change the HTML with ne new routes, the helpers make it right for you. Rails priorizes convention over configuration, and I think it's wonderful principle (model name = url path = db table) Hope it makes sense. |
Ah, I see! Not sure how we can make this work but we can certainly look into it. It pertains to the rendering engine which I was just talking about with @kennedymwavu needs a good revamp. |
@JohnCoene what error are you getting? all tests are passing on my end, albeit with some warnings (see attached). |
I had one failure which I just fixed, not sure what I did before |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm!
Allows nesting routers.
Instead of grabbing the routes, receivers (websocket handlers), and middlewares when the router is passed to
use
we delay that execution untilstart
where we recursively go through all 3 items. Doing so recursively means we can nest as many routers as we want.@kennedymwavu probably needs more testing, I haven't tested middlewares but this should work too. It's useful if, for instance, you have a specific middleware to check for authentication that you only want to apply to a subset of routes that are protected, e.g.: homepage will likely not require authentication while all routes in
/app
may require auth.