Chapter 50: Build a Full-Stack App in Rust

Put it all together: a complete project. In this chapter, you will learn build a full-stack app in depth with Rust code examples, explanations, and best practices.

Overview

This chapter covers build a full-stack app for Kungfu.js developers using Rust. We will start with the basics, move through practical examples, and end with advanced techniques and common pitfalls.

Why This Matters

Understanding build a full-stack app is essential because it is a core part of building web applications. Every real-world app needs to handle put it all together: a complete project. Skipping this chapter would leave a gap in your knowledge that would cause problems later.

Code Example

Building a Complete Application

In this final chapter, we will combine everything you have learned into a complete full-stack application. We will build a todo app with:

  • Database (SQLite) with CRUD operations
  • JWT authentication
  • WebSocket for real-time updates
  • CSS engine for styling
  • SSR with .kng files
  • Auto-generated API docs
  • Docker deployment

Project Structure

Here is how the complete todo app is organized. Every file is shown below so you can build it yourself without leaving this tutorial:

// src/main.rs — complete todo app
use kungfu::Kungfu;
use kungfu_orm::{Db, DbConfig};
use kungfu_core::{Method, Response, StatusCode};

#[derive(kungfu_macros::Model, serde::Serialize, serde::Deserialize)]
#[table(name = "todos")]
struct Todo {
    #[field(primary, auto_increment)]
    id: i64,
    title: String,
    #[field(default = "false")]
    done: bool,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let db = Db::connect(DbConfig {
        url: "sqlite://todos.db".into(),
        max_connections: 5,
        min_connections: 1,
    }).await?;
    db.migrate(&[Todo::create_table_sql()]).await?;

    Kungfu::new()
        .handle_get("/api/todos", move |_req, res| {
            let db = db.clone();
            Box::pin(async move {
                let todos = Todo::all(&db).await.unwrap_or_default();
                res.json(serde_json::to_string(&todos).unwrap())
            })
        })
        .handle_post("/api/todos", move |req, res| {
            let db = db.clone();
            Box::pin(async move {
                let body: Todo = serde_json::from_str(&req.body)?;
                let created = body.insert(&db).await?;
                res.status(StatusCode::Created)
                    .json(serde_json::to_string(&created)?)
            })
        })
        .ws("/ws", |ws| {
            // Broadcast new todos to all connected clients
            Box::pin(async move { ws.broadcast("todo_created").await })
        })
        .run("0.0.0.0:3000").await?;
    Ok(())
}

How the Pieces Fit Together

The Rust core handles HTTP parsing, routing, and the WebSocket connection. The Rust binding registers route handlers that call into the ORM for database operations. The .kng files handle the frontend — data() fetches todos from the API, template() renders them as HTML, and the hydration script makes the page interactive. When a todo is created, the server broadcasts a WebSocket message to all connected clients, and the UI updates in real time without a page refresh.

Running the App

cargo run
# Then open http://localhost:3000 in your browser

Congratulations!

You have completed all 50 chapters of the Kungfu.js tutorial for Rust. You now know how to build, secure, test, and deploy production-grade web applications with Kungfu.js.

What to do next:

  • Build your own project using what you learned
  • Share what you built with the community
  • Write about your experience with Kungfu.js
  • Help others learn by answering questions

Common Mistakes

  • Not reading the documentation: Always check the API reference when something does not work as expected.
  • Skipping security: Never disable the default middleware unless you have a very good reason. Security is not optional.
  • Not testing: Write tests for your handlers. Kungfu.js makes this easy with the built-in test utilities.

Summary

In this chapter, you learned about build a full-stack app in Rust. You saw code examples, understood how things work under the hood, and learned about common mistakes to avoid.