use std::net::Ipv4Addr;
use kynos::{
openapi::{Method, PathTemplate},
prelude::*,
router::{
endpoint::builder::EndpointBuilder,
policy::{FallbackPolicy, TrailingSlashPolicy},
},
server::Server,
};
#[derive(Tag)]
struct Users;
#[derive(Tag)]
#[tag(name = "ops", description = "Health and readiness")]
struct Ops;
#[derive(Tag)]
#[tag(name = "admin", description = "Restricted to staff")]
struct Admin;
#[kynos::get("/live", tag = Ops)]
async fn live() -> NoContent {
NoContent
}
#[kynos::get("/ready", tag = Ops)]
async fn ready() -> NoContent {
NoContent
}
#[kynos::get("/", catch_panics)]
async fn list_users() -> NoContent {
NoContent
}
#[kynos::get("/{id}")]
async fn get_user(Path(path): Path<UserPath>) -> NoContent {
println!("reading {}", path.id);
NoContent
}
#[allow(dead_code)]
#[derive(Schema, PathParams)]
struct UserPath {
id: u64,
}
#[kynos::operation(method = "PATCH", path = "/{id}/suspension", tag = Admin)]
async fn suspend_user(Path(path): Path<UserPath>) -> NoContent {
println!("suspending {}", path.id);
NoContent
}
fn admin_router() -> Router<()> {
Router::<()>::new()
.tag::<Admin>()
.mount(kynos::routes![suspend_user])
}
fn dynamic_router() -> Router<()> {
let endpoint = EndpointBuilder::new(
Method::Get,
PathTemplate::parse("/version").expect("valid path"),
version,
)
.operation_id("getVersion")
.summary("The running build")
.tag::<Ops>()
.deprecated();
Router::<()>::new().mount(endpoint)
}
async fn version() -> NoContent {
NoContent
}
#[tokio::main]
async fn main() -> kynos::Result<()> {
let router = Router::<()>::new()
.tag::<Ops>()
.group(
Group::new("/users")
.tag::<Users>()
.mount(kynos::routes![list_users, get_user]),
)
.nest("/admin", admin_router())
.merge(dynamic_router())
.mount(kynos::routes![live, ready])
.not_found(FallbackPolicy::Problem)
.method_not_allowed(FallbackPolicy::Problem)
.trailing_slashes(TrailingSlashPolicy::Redirect);
for violation in router.validate()? {
println!("{violation}");
}
let document = router.openapi()?;
println!("{}", document.to_json()?);
Server::new(router.build(())?)
.bind((Ipv4Addr::UNSPECIFIED, 3000))
.serve()
.await
}