Controllers
A controller is a Dart class that extends Controller and groups related request handlers. Each handler method returns Future<String> — the HTTP response body.
Creating a Controller
import 'package:finch/finch_route.dart';
class UserController extends Controller {
UserController();
@override
Future<String> index() async {
return rq.renderData(data: {'message': 'User list'});
}
Future<String> show() async {
var id = rq.getParam('id');
return rq.renderData(data: {'id': id});
}
Future<String> profile() async {
rq.addParam('title', 'User Profile');
return rq.renderView(path: 'user/profile');
}
}
The rq Object
Inside any Controller subclass, rq is a getter that returns Context.rq — the current Request object. It gives access to request data, session, cookies, and all response methods.
Attaching a Controller to a Route
final userController = UserController();
FinchRoute(
key: 'users.index',
path: 'users',
methods: Methods.ONLY_GET,
controller: userController, // calls userController.index()
),
FinchRoute(
key: 'users.show',
path: 'users/{id}',
methods: Methods.ONLY_GET,
index: userController.show, // calls a specific method
),
controller uses the index() method. index accepts a Future<String> Function()? — pass a method reference from the controller to call a different action.
Response Methods
All response methods are on the rq object:
| Method | Description |
|---|---|
rq.renderView(path: 'template/path') |
Render a Jinja template from widgetsPath |
rq.renderData(data: {...}) |
JSON response |
rq.renderString(text: '...') |
Plain text response |
rq.renderHtml(html: '...') |
HTML string response |
rq.renderTag(tag: Tag) |
Render an Htmler Tag |
rq.renderError(404) |
Standard error response |
rq.redirect('/path') |
HTTP redirect |
rq.renderSSE(stream) |
Server-Sent Events stream |
rq.renderSocket() |
WebSocket handshake |
renderView
Future<String> dashboard() async {
rq.addParams({
'title': 'Dashboard',
'user': currentUser,
});
return rq.renderView(path: 'pages/dashboard');
// Loads: widgetsPath/pages/dashboard.{widgetsType}
}
renderData (JSON)
Future<String> apiUsers() async {
var users = await UserCollection().getAll();
return rq.renderData(data: {'users': users.map((u) => u.toJson()).toList()});
}
renderError
Future<String> notFound() async {
return rq.renderError(404);
}
Reading Request Data
// Read a GET or POST field
var name = rq.get<String>('name', def: 'anonymous');
var age = rq.get<int>('age', def: 0);
// Read a path parameter from {id}
var id = rq.getParam('id');
// Check request method
if (rq.isPost) { ... }
if (rq.method == Methods.DELETE) { ... }
// API endpoint? (path starts with /api/)
bool isApi = rq.isApiEndpoint;
Passing Data to Templates
Future<String> show() async {
var user = await UserCollection().findById(rq.getParam('id'));
// addParam / addParams makes data available in Jinja templates
rq.addParams({
'user': user?.toJson(),
'title': 'User Profile',
});
return rq.renderView(path: 'user/show');
}
In the template:
<h1>{{ user.name }}</h1>
Accessing Other Controllers
Controllers are plain Dart objects. Instantiate them at the top level and share:
final authController = AppAuthController();
final homeController = HomeController();
// In AuthController.loginPost():
return homeController.renderView('example/form');