feat(api): add Leptos server functions bridging client and server
- Add src/api/ module with server functions for networks, hosts, applications - Each server function retrieves the pool via use_context::<AnyPool>() - Pool is injected via provide_context in two places in main.rs: * leptos_routes_with_context: for SSR renders and inline server fn calls * handle_server_fns_with_context on /api/*fn_name: for WASM client calls - create_host validates IP against network CIDR before inserting - create_network validates CIDR format before inserting Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
53
src/main.rs
53
src/main.rs
@@ -17,8 +17,11 @@
|
||||
async fn main() {
|
||||
use axum::Router;
|
||||
use leptos::config::get_configuration;
|
||||
use leptos::prelude::provide_context;
|
||||
use leptos::view;
|
||||
use leptos_axum::{generate_route_list, LeptosRoutes};
|
||||
use leptos_axum::{
|
||||
generate_route_list, handle_server_fns_with_context, LeptosRoutes,
|
||||
};
|
||||
use rust_ipam::{
|
||||
app::{App, Shell},
|
||||
server::{
|
||||
@@ -77,6 +80,12 @@ async fn main() {
|
||||
// that Leptos SSR must handle.
|
||||
let routes = generate_route_list(App);
|
||||
|
||||
// Clone the pool so we can inject it into two different contexts:
|
||||
// 1. `leptos_routes_with_context` — SSR rendering + server functions called during SSR
|
||||
// 2. `handle_server_fns_with_context` — server functions called from the WASM client
|
||||
let pool_for_routes = state.db.clone();
|
||||
let pool_for_fns = state.db.clone();
|
||||
|
||||
// Build the Axum router using the builder pattern (method chaining).
|
||||
//
|
||||
// `Router::<AppState>::new()` explicitly tells Rust the state type is `AppState`.
|
||||
@@ -86,16 +95,40 @@ async fn main() {
|
||||
// Serve static files compiled by trunk (WASM, JS...).
|
||||
// Trunk places them in target/site/pkg/ as configured in [package.metadata.leptos].
|
||||
.nest_service("/pkg", ServeDir::new("target/site/pkg"))
|
||||
// Handle server function HTTP calls from the WASM client.
|
||||
//
|
||||
// `#[server]` functions register themselves at "/api/<fn-name>".
|
||||
// `handle_server_fns_with_context` runs the server function body and injects
|
||||
// `additional_context` into the Leptos context before execution,
|
||||
// so server functions can call `use_context::<AnyPool>()` to get the pool.
|
||||
.route(
|
||||
"/api/*fn_name",
|
||||
axum::routing::post({
|
||||
let pool = pool_for_fns;
|
||||
move |req| {
|
||||
let pool = pool.clone();
|
||||
handle_server_fns_with_context(
|
||||
move || provide_context(pool.clone()),
|
||||
req,
|
||||
)
|
||||
}
|
||||
}),
|
||||
)
|
||||
// Mount all Leptos routes into Axum.
|
||||
// For each URL, Axum renders Shell() to HTML and sends it to the browser.
|
||||
// `leptos_routes` receives `&state` (the full AppState).
|
||||
// It extracts `LeptosOptions` via `FromRef<AppState>` implemented in state.rs.
|
||||
.leptos_routes(&state, routes, {
|
||||
// Clone options before moving into the closure.
|
||||
// `move` transfers ownership of `leptos_options` into the closure.
|
||||
let leptos_options = state.leptos_options.clone();
|
||||
move || view! { <Shell options=leptos_options.clone()/> }
|
||||
})
|
||||
// `leptos_routes_with_context` injects the pool into the Leptos context
|
||||
// for every SSR render — needed for server functions called during SSR
|
||||
// (e.g. when a `Resource` pre-fetches data on the server).
|
||||
.leptos_routes_with_context(
|
||||
&state,
|
||||
routes,
|
||||
{
|
||||
move || provide_context(pool_for_routes.clone())
|
||||
},
|
||||
{
|
||||
let leptos_options = state.leptos_options.clone();
|
||||
move || view! { <Shell options=leptos_options.clone()/> }
|
||||
},
|
||||
)
|
||||
.fallback(not_found_handler)
|
||||
// Share AppState (Leptos options + DB pool) with all handlers.
|
||||
.with_state(state);
|
||||
|
||||
Reference in New Issue
Block a user