// FastAPI's `APIRouter` + `include_router`: routes written away from any
// application and folded into one later, so a large API can be split by feature
// without every piece having to know the app it ends up on — and so the
// attributes a whole group shares (a prefix, tags, a security requirement) are
// stated once at the join rather than copied onto every route.
//
// `App::mount` is the other composition primitive and answers a different
// question: a mount stays a separate application behind a prefix, with its own
// middleware and lifespan, while an included router's routes become the parent's
// own — indistinguishable, afterwards, from routes registered on it directly.
///|
/// A collection of routes built away from any application and folded into one
/// with `App::include_router` (← FastAPI's `APIRouter`). It carries the registration
/// surface of an `App` and nothing else: middleware, mounts, security schemes,
/// documentation and lifespan belong to the application that includes it.
pub struct Router {
routes : Array[Route]
ws_routes : Array[@socket.WsRoute]
}
///|
/// An empty router. The prefix and the attributes its routes share are given at
/// `App::include_router` rather than here, so one router can be included twice
/// — under a second prefix, or on another app with different tags.
pub fn Router::new() -> Router {
{ routes: [], ws_routes: [], }
}
///|
/// Register a route on the router for an explicit method. Takes what
/// `App::route` takes and means the same by it; the route reaches an application
/// when the router is included.
pub fn Router::route(
self : Router,
verb : Method,
path : String,
handler : ApiHandler,
summary~ : String = "",
description~ : String = "",
tags~ : Array[String] = [],
deprecated~ : Bool = false,
operation_id~ : String = "",
status_code? : Int32,
responses~ : Array[@endpoint.ResponseSpec] = [],
name~ : String = "",
endpoint? : @endpoint.Endpoint,
security~ : Array[@security.SecurityRequirement] = [],
dependencies~ : Array[String] = [],
include_in_schema~ : Bool = true,
validate~ : Bool = true,
openapi_extra? : Json,
) -> Unit {
self.routes.push({
verb,
path,
run: (ctx, _bg) => Buffered(handler(ctx)),
summary,
description,
tags,
deprecated,
operation_id,
status_code,
responses,
name,
openapi_extra,
endpoint,
security,
dependencies,
include_in_schema,
validate,
})
}
///|
/// Register a background-aware route on the router — `App::route_bg`, deferred
/// to whichever application includes it.
pub fn Router::route_bg(
self : Router,
verb : Method,
path : String,
handler : BackgroundHandler,
summary~ : String = "",
description~ : String = "",
tags~ : Array[String] = [],
deprecated~ : Bool = false,
operation_id~ : String = "",
status_code? : Int32,
responses~ : Array[@endpoint.ResponseSpec] = [],
name~ : String = "",
endpoint? : @endpoint.Endpoint,
security~ : Array[@security.SecurityRequirement] = [],
dependencies~ : Array[String] = [],
include_in_schema~ : Bool = true,
validate~ : Bool = true,
openapi_extra? : Json,
) -> Unit {
self.routes.push({
verb,
path,
run: (ctx, bg) => Buffered(handler(ctx, bg)),
summary,
description,
tags,
deprecated,
operation_id,
status_code,
responses,
name,
openapi_extra,
endpoint,
security,
dependencies,
include_in_schema,
validate,
})
}
///|
/// Register a streaming `GET` route on the router — `App::stream`, deferred to
/// whichever application includes it.
pub fn Router::stream(
self : Router,
path : String,
handler : StreamHandler,
summary~ : String = "",
description~ : String = "",
tags~ : Array[String] = [],
deprecated~ : Bool = false,
operation_id~ : String = "",
status_code? : Int32,
responses~ : Array[@endpoint.ResponseSpec] = [],
name~ : String = "",
endpoint? : @endpoint.Endpoint,
security~ : Array[@security.SecurityRequirement] = [],
dependencies~ : Array[String] = [],
include_in_schema~ : Bool = true,
validate~ : Bool = true,
openapi_extra? : Json,
) -> Unit {
self.routes.push({
verb: Get,
path,
run: (ctx, _bg) => Streamed(handler(ctx)),
summary,
description,
tags,
deprecated,
operation_id,
status_code,
responses,
name,
openapi_extra,
endpoint,
security,
dependencies,
include_in_schema,
validate,
})
}
///|
/// Register a `GET` route on the router.
pub fn Router::get(
self : Router,
path : String,
handler : ApiHandler,
summary~ : String = "",
description~ : String = "",
tags~ : Array[String] = [],
deprecated~ : Bool = false,
operation_id~ : String = "",
status_code? : Int32,
responses~ : Array[@endpoint.ResponseSpec] = [],
name~ : String = "",
endpoint? : @endpoint.Endpoint,
security~ : Array[@security.SecurityRequirement] = [],
dependencies~ : Array[String] = [],
include_in_schema~ : Bool = true,
validate~ : Bool = true,
openapi_extra? : Json,
) -> Unit {
self.route(
Get,
path,
handler,
summary~,
description~,
tags~,
deprecated~,
operation_id~,
status_code?,
responses~,
name~,
endpoint?,
security~,
dependencies~,
include_in_schema~,
validate~,
openapi_extra?,
)
}
///|
/// Register a `POST` route on the router.
pub fn Router::post(
self : Router,
path : String,
handler : ApiHandler,
summary~ : String = "",
description~ : String = "",
tags~ : Array[String] = [],
deprecated~ : Bool = false,
operation_id~ : String = "",
status_code? : Int32,
responses~ : Array[@endpoint.ResponseSpec] = [],
name~ : String = "",
endpoint? : @endpoint.Endpoint,
security~ : Array[@security.SecurityRequirement] = [],
dependencies~ : Array[String] = [],
include_in_schema~ : Bool = true,
validate~ : Bool = true,
openapi_extra? : Json,
) -> Unit {
self.route(
Post,
path,
handler,
summary~,
description~,
tags~,
deprecated~,
operation_id~,
status_code?,
responses~,
name~,
endpoint?,
security~,
dependencies~,
include_in_schema~,
validate~,
openapi_extra?,
)
}
///|
/// Register a `PUT` route on the router.
pub fn Router::put(
self : Router,
path : String,
handler : ApiHandler,
summary~ : String = "",
description~ : String = "",
tags~ : Array[String] = [],
deprecated~ : Bool = false,
operation_id~ : String = "",
status_code? : Int32,
responses~ : Array[@endpoint.ResponseSpec] = [],
name~ : String = "",
endpoint? : @endpoint.Endpoint,
security~ : Array[@security.SecurityRequirement] = [],
dependencies~ : Array[String] = [],
include_in_schema~ : Bool = true,
validate~ : Bool = true,
openapi_extra? : Json,
) -> Unit {
self.route(
Put,
path,
handler,
summary~,
description~,
tags~,
deprecated~,
operation_id~,
status_code?,
responses~,
name~,
endpoint?,
security~,
dependencies~,
include_in_schema~,
validate~,
openapi_extra?,
)
}
///|
/// Register a `PATCH` route on the router.
pub fn Router::patch(
self : Router,
path : String,
handler : ApiHandler,
summary~ : String = "",
description~ : String = "",
tags~ : Array[String] = [],
deprecated~ : Bool = false,
operation_id~ : String = "",
status_code? : Int32,
responses~ : Array[@endpoint.ResponseSpec] = [],
name~ : String = "",
endpoint? : @endpoint.Endpoint,
security~ : Array[@security.SecurityRequirement] = [],
dependencies~ : Array[String] = [],
include_in_schema~ : Bool = true,
validate~ : Bool = true,
openapi_extra? : Json,
) -> Unit {
self.route(
Patch,
path,
handler,
summary~,
description~,
tags~,
deprecated~,
operation_id~,
status_code?,
responses~,
name~,
endpoint?,
security~,
dependencies~,
include_in_schema~,
validate~,
openapi_extra?,
)
}
///|
/// Register a `DELETE` route on the router.
pub fn Router::delete(
self : Router,
path : String,
handler : ApiHandler,
summary~ : String = "",
description~ : String = "",
tags~ : Array[String] = [],
deprecated~ : Bool = false,
operation_id~ : String = "",
status_code? : Int32,
responses~ : Array[@endpoint.ResponseSpec] = [],
name~ : String = "",
endpoint? : @endpoint.Endpoint,
security~ : Array[@security.SecurityRequirement] = [],
dependencies~ : Array[String] = [],
include_in_schema~ : Bool = true,
validate~ : Bool = true,
openapi_extra? : Json,
) -> Unit {
self.route(
Delete,
path,
handler,
summary~,
description~,
tags~,
deprecated~,
operation_id~,
status_code?,
responses~,
name~,
endpoint?,
security~,
dependencies~,
include_in_schema~,
validate~,
openapi_extra?,
)
}
///|
/// Register a WebSocket route on the router (← `APIRouter.websocket`). It takes
/// the including prefix like any other route; the operation attributes do not
/// apply, since a WebSocket route is not an OpenAPI operation.
pub fn Router::websocket(
self : Router,
path : String,
handler : @socket.WsHandler,
) -> Unit {
self.ws_routes.push({ path, handler, })
}