ruskit 0.1.5

A modern web framework for Rust inspired by Laravel
Documentation
{% extends "docs_base.html" %}

{% block content %}
<div class="prose prose-slate max-w-none">
    <h1>Routing in Ruskit</h1>

    <p>Ruskit provides a simple and expressive routing system built on top of Axum. This guide will help you understand how to define routes and handle HTTP requests in your Ruskit application.</p>

    <h2>Basic Routing</h2>

    <p>The most basic Ruskit routes accept a URI and a closure or function handler:</p>

    <pre><code class="language-rust">Router::new()
    .route("/", get(home))</code></pre>

    <h3>Available Router Methods</h3>

    <p>You may register routes for any HTTP verb using the corresponding methods:</p>

    <pre><code class="language-rust">Router::new()
    .route("/users", get(users_index))         // GET
    .route("/users", post(users_store))        // POST
    .route("/users/{id}", put(users_update))   // PUT
    .route("/users/{id}", delete(users_delete)) // DELETE</code></pre>

    <h2>Route Handlers</h2>

    <p>Route handlers in Ruskit can return different types of responses:</p>

    <h3>Basic String Response</h3>
    <pre><code class="language-rust">async fn home() -> &'static str {
    "Welcome to Ruskit!"
}</code></pre>

    <h3>JSON Response</h3>
    <pre><code class="language-rust">async fn users_index() -> Json<Value> {
    Json(json!({ "message": "List of users" }))
}</code></pre>

    <h2>Route Parameters</h2>

    <h3>Required Parameters</h3>

    <p>You can capture route segments using curly braces <code>{}</code>:</p>

    <pre><code class="language-rust">// Route definition
.route("/users/{id}", get(users_show))

// Handler
async fn users_show(Path(id): Path<String>) -> Json<Value> {
    Json(json!({
        "message": "Show user details",
        "id": id
    }))
}</code></pre>

    <h2>API Routes</h2>

    <p>When building an API, you'll typically want to group related routes under an API prefix:</p>

    <pre><code class="language-rust">Router::new()
    .route("/api/users", get(users_index))
    .route("/api/users/{id}", get(users_show))
    .route("/api/users", post(users_store))</code></pre>

    <h2>Example Routes File</h2>

    <p>Here's a complete example of a routes file in Ruskit:</p>

    <pre><code class="language-rust">use axum::{
    Router,
    routing::{get, post},
    response::Json,
    extract::Path,
};
use serde_json::{json, Value};

// Basic route handler
async fn home() -> &'static str {
    "Welcome to Ruskit!"
}

// JSON API handlers
async fn users_index() -> Json<Value> {
    Json(json!({ "message": "List of users" }))
}

async fn users_show(Path(id): Path<String>) -> Json<Value> {
    Json(json!({
        "message": "Show user details",
        "id": id
    }))
}

async fn users_store() -> Json<Value> {
    Json(json!({ "message": "Create new user" }))
}

// Define all routes
pub fn routes() -> Router {
    Router::new()
        .route("/", get(home))
        .route("/api/users", get(users_index))
        .route("/api/users/{id}", get(users_show))
        .route("/api/users", post(users_store))
}</code></pre>

    <h2>Request Data Handling</h2>

    <p>Ruskit provides elegant ways to access different types of request data using Axum's powerful extractors.</p>

    <h3>URL Parameters</h3>

    <p>You can capture URL parameters using curly braces in your route definition:</p>

    <pre><code class="language-rust">use axum::{extract::Path, Router};
use serde::Deserialize;

// Single parameter
async fn show_user(Path(id): Path<String>) -> Response {
    // Access id directly
}

// Multiple parameters
#[derive(Deserialize)]
struct UserPostParams {
    user_id: String,
    post_id: i32,
}

async fn show_user_post(
    Path(params): Path<UserPostParams>
) -> Response {
    // Access params.user_id and params.post_id
}

// In your router
Router::new()
    .route("/users/:id", get(show_user))
    .route("/users/:user_id/posts/:post_id", get(show_user_post))</code></pre>

    <h3>Query Parameters</h3>

    <p>Handle query parameters (e.g., <code>?page=1&limit=10</code>) using the <code>Query</code> extractor:</p>

    <pre><code class="language-rust">use axum::extract::Query;
use serde::Deserialize;

#[derive(Deserialize)]
struct PaginationParams {
    page: Option<u32>,
    limit: Option<u32>,
}

async fn list_users(
    Query(params): Query<PaginationParams>
) -> Response {
    let page = params.page.unwrap_or(1);
    let limit = params.limit.unwrap_or(10);
    // Use page and limit for pagination
}

// Optional query parameters with defaults
#[derive(Deserialize)]
struct FilterParams {
    #[serde(default = "default_status")]
    status: String,
    #[serde(default)]
    sort_by: String,
}

fn default_status() -> String {
    "active".to_string()
}

async fn filtered_users(
    Query(params): Query<FilterParams>
) -> Response {
    // params.status will be "active" if not provided
    // params.sort_by will be empty string if not provided
}</code></pre>

    <h3>Request Body</h3>

    <p>Handle POST, PUT, and PATCH request bodies using the <code>Json</code> extractor:</p>

    <pre><code class="language-rust">use axum::{
    extract::Json,
    response::IntoResponse,
};
use serde::{Deserialize, Serialize};

#[derive(Deserialize)]
struct CreateUser {
    username: String,
    email: String,
    password: String,
}

#[derive(Serialize)]
struct UserResponse {
    id: i32,
    username: String,
    email: String,
}

async fn create_user(
    Json(payload): Json<CreateUser>
) -> impl IntoResponse {
    // Access payload.username, payload.email, etc.
    Json(UserResponse {
        id: 1,
        username: payload.username,
        email: payload.email,
    })
}

// Handle form data
use axum::extract::Form;

#[derive(Deserialize)]
struct LoginForm {
    username: String,
    password: String,
}

async fn login(
    Form(data): Form<LoginForm>
) -> Response {
    // Handle form submission
}</code></pre>
</div>
{% endblock %}