salvo-routing
Configure Salvo routers with path parameters, nested routes, and filters. Use for complex routing structures and RESTful APIs.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Configure Salvo routers with path parameters, nested routes, and filters. Use for complex routing structures and RESTful APIs.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Guide for using RBatis v4 Rust ORM framework. Use when implementing database CRUD operations, writing dynamic SQL with py_sql or html_sql macros, configuring database connections, managing transactions, implementing interceptors, syncing table structures, or integrating RBatis into Genies microservices. Also use when the user asks about RBatis usage patterns, query building, or database operations in Rust.
Genies 前后端接口规范。Use when designing API contracts, defining field naming conventions, date/time formats, response models, pagination, error handling, or ID strategies between Genies backend and frontend (Web/Android/OHOS).
Guide for using flyway-rs database migration framework with RBatis. Use when implementing database schema migrations, managing SQL changelog files, configuring migration runners, handling multi-database migrations, or integrating database versioning into Genies microservices.
Guide for developing Rust microservices using Genies framework following Java DDD layering principles. Use when creating new microservices, designing aggregate roots, implementing domain events, organizing service layers, setting up Flyway migrations, or structuring a DDD-based Genies project.
Genies framework unified skill hub. Use when you need to find the right skill for any Genies framework task, including authentication, authorization, caching, configuration, database, DDD microservices, Dapr messaging, macros, K8s deployment, testing, API conventions, gateway proxy, or Salvo web framework features. Also use when the user asks about Genies framework capabilities, asks which skill to use, or wants a quick overview of available Genies skills.
Guide for using the Genies Rust microservice framework with DDD and Dapr. Use when developing with Genies, creating aggregates, domain events, Dapr subscriptions, Casbin field-level permissions, configuration management, or when the user asks about Genies framework usage patterns.
| name | salvo-routing |
| description | Configure Salvo routers with path parameters, nested routes, and filters. Use for complex routing structures and RESTful APIs. |
| version | 0.89.3 |
| tags | ["core","routing","path-params","filters"] |
This skill helps configure advanced routing patterns in Salvo applications.
Salvo's routing system has unique features:
hoop() methodpush() for arbitrary depth hierarchical structuresRouter::with_path("users").get(list_users)
Salvo uses {id} syntax for path parameters (since version 0.76). Earlier versions used <id> syntax, which is now deprecated.
// Basic parameter
Router::with_path("users/{id}").get(show_user)
// Typed parameter (num, i32, i64, etc.)
Router::with_path("users/{id:num}").get(show_user)
// Regex pattern
Router::with_path(r"users/{id|\d+}").get(show_user)
// Wildcard (captures rest of path)
Router::with_path("files/{**path}").get(serve_file)
#[handler]
async fn show_user(req: &mut Request) -> String {
let id = req.param::<i64>("id").unwrap();
format!("User ID: {}", id)
}
Salvo supports multiple wildcard patterns (using {} syntax since version 0.76; earlier versions used <> syntax):
{*}: Matches any single path segment
Router::new().path("{*}").get(catch_all)
{**}: Matches all remaining path segments (including slashes)
Router::new().path("static/{**path}").get(serve_static)
// Matches: static/css/style.css, static/js/main.js, etc.
Named wildcards: Can retrieve matched content in handler
Router::new().path("files/{*rest}").get(handler)
// In handler: req.param::<String>("rest")
let router = Router::new()
.push(
Router::with_path("api/v1")
.push(
Router::with_path("users")
.get(list_users)
.post(create_user)
.push(
Router::with_path("{id}")
.get(show_user)
.patch(update_user)
.delete(delete_user)
)
)
.push(
Router::with_path("posts")
.get(list_posts)
.post(create_post)
)
);
fn user_routes() -> Router {
Router::with_path("users")
.get(list_users)
.post(create_user)
.push(
Router::with_path("{id}")
.get(get_user)
.patch(update_user)
.delete(delete_user)
)
}
fn post_routes() -> Router {
Router::with_path("posts")
.get(list_posts)
.post(create_post)
}
let api_v1 = Router::with_path("v1")
.push(user_routes())
.push(post_routes());
let api_v2 = Router::with_path("v2")
.push(user_routes())
.push(post_routes());
let router = Router::new()
.push(Router::with_path("api/v1/users").get(list_users).post(create_user))
.push(Router::with_path("api/v1/users/{id}").get(show_user).patch(update_user).delete(delete_user));
Router::new()
.get(handler) // GET
.post(handler) // POST
.put(handler) // PUT
.patch(handler) // PATCH
.delete(handler) // DELETE
.head(handler) // HEAD
.options(handler); // OPTIONS
When a request arrives, routing works as follows:
use salvo::routing::filters;
// Path filter
Router::with_filter(filters::path("users"))
// Method filter
Router::with_filter(filters::get())
// Combined filters
Router::with_filter(filters::path("users").and(filters::get()))
Use hoop() to add middleware to routes:
let router = Router::new()
.hoop(logging) // Applies to all routes
.path("api")
.push(
Router::new()
.hoop(auth_check) // Only applies to routes under this
.path("users")
.get(list_users)
.post(create_user)
);
use salvo::prelude::*;
use salvo::writing::Redirect;
// Permanent redirect (301)
#[handler]
async fn permanent_redirect(res: &mut Response) {
res.render(Redirect::permanent("/new-location"));
}
// Temporary redirect (302)
#[handler]
async fn temporary_redirect(res: &mut Response) {
res.render(Redirect::found("/temporary-location"));
}
// See Other (303)
#[handler]
async fn see_other(res: &mut Response) {
res.render(Redirect::see_other("/another-page"));
}
Create custom filters for complex matching logic:
use salvo::prelude::*;
use salvo::routing::filter::Filter;
use uuid::Uuid;
pub struct GuidFilter;
impl Filter for GuidFilter {
fn filter(&self, req: &mut Request, _state: &mut PathState) -> bool {
if let Some(param) = req.param::<String>("id") {
Uuid::parse_str(¶m).is_ok()
} else {
false
}
}
}
#[handler]
async fn get_user_by_guid(req: &mut Request) -> String {
let id = req.param::<Uuid>("id").unwrap();
format!("User GUID: {}", id)
}
let router = Router::new()
.path("users/{id}")
.filter(GuidFilter)
.get(get_user_by_guid);
{id:/\d+/}){id} syntax for consistency