///|
/// A route group: registers a set of routes on an underlying `moonapi.App` under
/// a shared path prefix and a shared set of route options, so related endpoints
/// (everything under `/api/v1`, say) are declared without repeating either.
pub struct Group {
app : @moonapi.App
prefix : String
options : RouteOptions
}
///|
/// Open a group that prefixes every route it registers with `prefix` on `app`.
pub fn Group::new(app : @moonapi.App, prefix : String) -> Group {
{ app, prefix, options: RouteOptions::new(), }
}
///|
/// The prefix this group joins onto each registered route.
pub fn Group::prefix(self : Group) -> String {
self.prefix
}
///|
/// The options every route in this group inherits.
pub fn Group::options(self : Group) -> RouteOptions {
self.options
}
///|
/// A group that keeps this one's prefix and app with `options` in place of the
/// inherited set. The prefixes still join, so
/// `Group::new(app, "/api").options_(RouteOptions::new().under("/v1"))` serves
/// `/api/v1/...`.
pub fn Group::options_(self : Group, options : RouteOptions) -> Group {
{ app: self.app, prefix: self.prefix, options, }
}
///|
/// A sub-group under `prefix`, inheriting every option.
pub fn Group::sub(self : Group, prefix : String) -> Group {
{
app: self.app,
prefix: join_prefix(self.prefix, prefix),
options: self.options,
}
}
///|
/// Register a route for an explicit method under the group's prefix and options.
pub fn Group::route(
self : Group,
verb : @moonapi.Method,
path : String,
handler : @moonapi.ApiHandler,
summary~ : String = "",
) -> Unit {
let full = template(
join_prefix(join_prefix(self.prefix, self.options.prefix), path),
)
self.app.route(verb, full, handler, summary~, hoops=hoops_of(self.options))
}
///|
/// Register a `GET` route under the group's prefix.
pub fn Group::get(
self : Group,
path : String,
handler : @moonapi.ApiHandler,
summary~ : String = "",
) -> Unit {
self.route(Get, path, handler, summary~)
}
///|
/// Register a `POST` route under the group's prefix.
pub fn Group::post(
self : Group,
path : String,
handler : @moonapi.ApiHandler,
summary~ : String = "",
) -> Unit {
self.route(Post, path, handler, summary~)
}
///|
/// Register a `PUT` route under the group's prefix.
pub fn Group::put(
self : Group,
path : String,
handler : @moonapi.ApiHandler,
summary~ : String = "",
) -> Unit {
self.route(Put, path, handler, summary~)
}
///|
/// Register a `PATCH` route under the group's prefix.
pub fn Group::patch(
self : Group,
path : String,
handler : @moonapi.ApiHandler,
summary~ : String = "",
) -> Unit {
self.route(Patch, path, handler, summary~)
}
///|
/// Register a `DELETE` route under the group's prefix.
pub fn Group::delete(
self : Group,
path : String,
handler : @moonapi.ApiHandler,
summary~ : String = "",
) -> Unit {
self.route(Delete, path, handler, summary~)
}
///|
/// Register a server-sent-events route: a `GET` that answers with
/// `text/event-stream` and is not cached.
pub fn Group::sse(
self : Group,
path : String,
handler : @moonapi.ApiHandler,
summary~ : String = "",
) -> Unit {
self.options_(self.options.sse()).get(path, handler, summary~)
}
///|
/// A go-zero path as moonapi writes it: go-zero names a path parameter `:id`,
/// moonapi `{id}`, so a route copied from an `.api` file registers unchanged.
fn template(path : String) -> String {
path
.split("/")
.map(segment => {
if segment.has_prefix(":") {
"{" + segment.exact_view(start=1).to_owned() + "}"
} else {
segment.to_owned()
}
})
.collect()
.join("/")
}