Middleware
Filter HTTP requests and responses. Middleware enables cross-cutting concerns like authentication, logging, and CORS handling.
Middleware Attributes
Control behavior using special comment attributes:
app/middleware/logging.soli
// order: 10
// Execution order (lower runs first, default: 100)
fn log_request(req: Any) -> Any {
let timestamp = datetime::now();
println(timestamp + " " + req.method + " " + req.path);
return req;
}
// global_only: true
// Only run when applied globally
fn cors(req: Any) -> Any {
let response = req;
response.headers["Access-Control-Allow-Origin"] = "*";
return response;
}
// scope_only: true
// Only run when explicitly scoped
fn authenticate(req: Any) -> Any {
let token = req.headers["Authorization"];
if token == null { return error(401, "Unauthorized"); }
return req;
}
Creating Middleware
app/middleware/auth.soli
// order: 20
// scope_only: true
fn authenticate(req: Any) -> Any {
let token = req.headers["Authorization"];
if token == null || token == "" {
return error(401, "Unauthorized");
}
// Validate token
let user = validate_token(token);
if user == null {
return error(401, "Invalid token");
}
// Attach user to request
req["user"] = user;
return req;
}
Execution Order
Requests flow through middleware layers before reaching your controller.
Step 1
Global Middleware
(Sorted by order)
Step 2
Scoped Middleware
(Specific to route)
Target
Controller Action
Return
Response flows back up
Applying Middleware
config/routes.soli
// Global middleware (runs on every request)
use("middleware/logging");
use("middleware/cors");
// Scoped middleware (runs on specific routes)
get("/dashboard", "dashboard#index", ["auth"]);
// Combining scopes
get("/api/users", "api#users", ["auth", "rate_limit"]);
Best Practices
- • Use
orderto strictly control the execution sequence. - • Keep global middleware lightweight; expensive operations belong in scoped middleware.
- • Use
scope_only: truefor authentication to prevent accidental global application.