question: functional API?
A lot of the ambiorix examples have code like
https://github.com/ambiorix-web/ambiorix-examples/blob/main/06_multi_router/server.R
Ambiorix$
new()$
listen(port = 3000L)$
use(members$v1)$ # mount API v1 members' router
use(members$v2)$ # mount API v2 members' router
start(open = FALSE)
or
app <- Ambiorix$new()
app$error <- error_handler
app$
use(goal_router)$
use(user_router)$
start(port = get_port(), open = FALSE)
It would be nice if there were pipe-able alternatives. While I like R6 a lot, I think the use of $ to call methods may make some folks uneasy. A functional approach could be useful. Just spitballing here:
new_app <- function() Ambiorix$new()
abx_listen <- function(x, port) {
x$listen(port = port)
x
}
abx_use <- function(x, y) {
x$use(y)
x
}
abx_start <- function(x, ...) {
x$start(...)
x
}
new_app() |>
abx_use(goal_router) |>
abx_use(user_router) |>
abx_start()
The idea being that instead of method chaining each function applies a method and returns the modified object
I like amb_ intead of abx_, but I'm totally in whatever is decided.
@jrosell it's a purely superficial choice but i think it would make it feel better for some folks. Do you agree?
@JosiahParry i can see the appeal of the functional API—sure, it might feel better for some folks—but after tinkering with it for some time, i found the tradeoffs to be quite significant.
implementing a functional API would require duplicating every method tied to the request, response, ambiorix, & router classes, which means maintaining 4 parallel APIs. that adds overhead when introducing new methods, updating existing ones, or handling deprecations.
also, i think it's best to stick to a single, consistent approach. since ambiorix is designed around R6, introducing a functional alternative doesn’t add much value but does introduce the risk of fragmentation—where some parts of a codebase might use one style and others use another. sticking to OOP ensures predictability for users (existing and new alike) and avoids confusion as far as the syntax is concerned.
given all this, i don’t suppose the ROI would justify the added complexity.
Having only one oficial R6 API and generate the functional API could be great.
I guess we can use some metaprogramming approach here in R. One can do it with method_missing in Ruby.
Let me think about it.
I don't think it's a good idea.
Plumber did not have a programmatic API for much of its lifetime, it was added later on by Barrett and was certainly most welcome.
Ambiorix already has a programmatic API, duplicating the API to obtain a very slightly different syntax ($ => |>) does not seem advisable.
Besides, I've made this mistake in the past: R users are familiar with R6 syntax.