Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ pin-project = { version = "1.1.10" }
postcard = { version = "1.1.3", default-features = false }
serde_urlencoded = "0.7"
form_urlencoded = "1.2.1"
dashmap = "6.1.0"

# desktop
wry = { version = "0.52.1", default-features = false }
Expand Down Expand Up @@ -479,6 +480,7 @@ bytes = { workspace = true }
futures = { workspace = true }
axum-core = { workspace = true }
uuid = { workspace = true, features = ["v4", "serde"] }
dashmap = { workspace = true }
tower-http = { workspace = true, features = ["timeout"] }

[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
Expand Down Expand Up @@ -699,6 +701,11 @@ name = "flat_router"
path = "examples/06-routing/flat_router.rs"
doc-scrape-examples = true

[[example]]
name = "namespaced_server_functions"
path = "examples/07-fullstack/namespaced_server_functions.rs"
doc-scrape-examples = true

[[example]]
name = "middleware"
path = "examples/07-fullstack/middleware.rs"
Expand Down
104 changes: 104 additions & 0 deletions examples/07-fullstack/namespaced_server_functions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//! This example demonstrates how to define namespaced server functions in Dioxus Fullstack.
//!
//! Namespaced Server Functions allow you to organize your server functions into logical groups,
//! making it possible to reuse groups of functions as a library across different projects.
//!
//! Namespaced server functions are defined as methods on a struct. The struct itself is the "state"
//! of this group of functions, and can hold any data you want to share across the functions.
//!
//! Unlike regular server functions, namespaced server functions are not automatically registered
//! with `dioxus::launch`. You must explicitly mount the server functions to a given route using the
//! `Endpoint::mount` function. From the client, you can then call the functions using regular method
//! call syntax.
//!
//! Namespaces are designed to make server functions easier to modularize and reuse, making it possible
//! to create a publishable library of server functions that other developers can easily integrate into
//! their own Dioxus Fullstack applications.

use dioxus::fullstack::Endpoint;
use dioxus::prelude::*;

fn main() {
#[cfg(not(feature = "server"))]
dioxus::launch(app);

// On the server, we can customize the models and mount the server functions to a specific route.
// The `.endpoint()` extension method allows you to mount an `Endpoint<T>` to an axum router.
#[cfg(feature = "server")]
dioxus::serve(|| async move {
//
todo!()
});
}

// We mount a namespace of server functions to the "/api/dogs" route.
// All calls to `DOGS` from the client will be sent to this route.
static DOGS: Endpoint<PetApi> = Endpoint::new("/api/dogs", || PetApi { pets: todo!() });

/// Our server functions will be associated with this struct.
struct PetApi {
/// we can add shared state here if we want
/// e.g. a database connection pool
///
/// Since `PetApi` exists both on the client and server, we need to conditionally include
/// the database pool only on the server.
// #[cfg(feature = "server")]
pets: dashmap::DashMap<String, String>,
}

impl PetApi {
/// List all the pets in the database.
// #[get("/")]
async fn list(&self) -> Result<Vec<String>> {
Ok(self.pets.iter().map(|entry| entry.key().clone()).collect())
}

/// Get the breed of a specific pet by name.
// #[get("/{name}")]
async fn get(&self, name: String) -> Result<String> {
Ok(self
.pets
.get(&name)
.map(|entry| entry.value().clone())
.or_not_found("pet not found")?)
}

/// Add a new pet to the database.
// #[post("/{name}")]
async fn add(&self, name: String, breed: String) -> Result<()> {
self.pets.insert(name, breed);
Ok(())
}

/// Remove a pet from the database.
// #[delete("/{name}")]
async fn remove(&self, name: String) -> Result<()> {
self.pets.remove(&name).or_not_found("pet not found")?;
Ok(())
}

/// Update a pet's name in the database.
#[put("/{name}")]
async fn update(&self, name: String, breed: String) -> Result<()> {
self.pets.insert(breed.clone(), breed);
Ok(())
}
}

/// In our app, we can call the namespaced server functions using regular method call syntax, mixing
/// loaders, actions, and other hooks as normal.
fn app() -> Element {
let pets = use_loader(|| DOGS.list())?;
let add = use_action(|name, breed| DOGS.add(name, breed));
let remove = use_action(|name| DOGS.remove(name));
let update = use_action(|breed| DOGS.update(breed));

rsx! {
div {
h1 { "My Pets" }
ul {

}
}
}
}
2 changes: 2 additions & 0 deletions examples/07-fullstack/ssr-only/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
//!
//! To run this example, simply run `cargo run --package ssr-only` and navigate to `http://localhost:8080`.
use std::any::TypeId;

use dioxus::prelude::*;

fn main() {
Expand Down
8 changes: 8 additions & 0 deletions packages/fullstack-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ mod server_future;
mod streaming;
mod transport;

use std::{any::Any, sync::Arc};

pub use crate::errors::*;
pub use crate::loader::*;
pub use crate::server_cached::*;
Expand All @@ -28,3 +30,9 @@ pub use httperror::*;

#[derive(Clone, Default)]
pub struct DioxusServerState {}

impl DioxusServerState {
pub fn get_endpoint<T: Any>(&self) -> Option<Arc<T>> {
todo!()
}
}
Loading