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";
end
def index(req)
let posts = Post.all();
render("posts/index", {
"title": "All Posts",
"posts": posts
})
end
def show(req)
let id = req.params["id"];
let post = Post.find(id);
if post == null
return error(404, "Post not found");
end
render("posts/show", {
"title": post["title"],
"post": post
})
end
end
Lifecycle Hooks
Execute code before or after actions. Perfect for authentication or data loading.
this.layout
Set the layout template for all actions
this.before_action
Run code before action executes
this.after_action
Run code after action executes
class PostsController extends ApplicationController
static
# Set layout for all actions
this.layout = "layouts/posts";
# Run before ALL actions
this.before_action = def(req)
print("Processing: " + req.path);
req
end
# Run before SPECIFIC actions only
this.before_action(:show, :edit) = def(req)
let post = Post.find(req.params["id"]);
if post == null return error(404, "Not Found"); end
req["post"] = post; # Pass to action
req
end
# Run after SPECIFIC actions
this.after_action(:create, :update) = def(req, response)
# Log activity after create/update
print("Action completed");
response
end
end
# ... actions ...
end
Function-Based Controllers
Great for simple APIs or microservices where you don't need the full power of classes.
# GET /health
def health(req)
{
"status": 200,
"headers": {"Content-Type": "application/json"},
"body": "{\"status\":\"ok\"}"
}
end
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
render("home/index", { "title": "Welcome" })
redirect("/login")
{
"status": 200,
"headers": { "Content-Type": "application/json" },
"body": json_encode({ "data": posts })
}
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.