Controllers
Controllers are the heart of your application. They handle HTTP requests, process data, and determine the response. Soli supports both modern class-based controllers and simple function-based handlers.
Class-Based Controllers
Recommended for most applications. They provide structure, inheritance, and powerful hooks like before_action.
class PostsController extends ApplicationController {
static {
this.layout = "layouts/posts";
}
fn index(req: Any) -> Any {
let posts = Post.all();
return render("posts/index", {
"title": "All Posts",
"posts": posts
});
}
fn show(req: Any) -> Any {
let id = req.params["id"];
let post = Post.find(id);
if post == null {
return error(404, "Post not found");
}
return render("posts/show", {
"title": post["title"],
"post": post
});
}
}
Lifecycle Hooks
Execute code before or after actions. Perfect for authentication or data loading.
class PostsController extends ApplicationController {
static {
// Run before ALL actions
this.before_action = fn(req) {
print("Processing: " + req.path);
return req;
};
// Run before SPECIFIC actions only
this.before_action(:show, :edit) = fn(req) {
let post = Post.find(req.params["id"]);
if post == null { return error(404, "Not Found"); }
req["post"] = post; // Pass to action
return req;
};
}
// ... actions ...
}
Function-Based Controllers
Great for simple APIs or microservices where you don't need the full power of classes.
// GET /health
fn health(req: Any) -> Any {
return {
"status": 200,
"headers": {"Content-Type": "application/json"},
"body": "{\"status\":\"ok\"}"
};
}
The Request Object
Access all HTTP request details through the req parameter.
req.params
Route parameters & query strings
req.body
Raw request body content
req.headers
HTTP headers map
req.session
User session data storage
Response Types
return render("home/index", { "title": "Welcome" });
return redirect("/login");
return {
"status": 200,
"headers": { "Content-Type": "application/json" },
"body": json_encode({ "data": posts })
};
return error(404, "Page Not Found");
Pro Tip: Keep Controllers Thin
Delegate complex business logic to Models or Service objects. Controllers should primarily focus on handling the HTTP request and selecting the correct response.
Best Practices
- Use class-based controllers for better organization and reuse.
-
Create a base
ApplicationControllerto share logic like auth across all controllers. -
Use
before_actionto load resources and DRY up your code. -
Prefix private helper methods with
_to prevent them from becoming routes.