Code generation
What it is
Section titled “What it is”gisila’s routing is written by a build_runner generator. For each @Controller class it emits an attachToApp(GisilaApp app, Router router, {String prefix}) extension method into the file’s .g.dart part. That method registers every route on a shelf_router Router, with the parameter binding, the merged route config and the response rendering spelled out as plain Dart.
When to use it
Section titled “When to use it”Always, for annotated controllers: the annotations do nothing without it. Run it after changing an annotation, a route path, a parameter or a return type.
When not to use it
Section titled “When not to use it”You can skip the generator for individual routes by writing a ControllerAttacher by hand that registers Shelf handlers (wrapped in gisilaRoute to keep guards and limits). That is useful for a few unusual endpoints, but for ordinary routes the generated code is shorter and harder to get wrong.
How it works
Section titled “How it works”Dart has no runtime reflection in AOT-compiled servers, so gisila reads annotations at build time instead:
build_runnerruns the gisila builder on every library in your package (it is auto-applied to packages that depend on gisila).- For each
@Controllerclass, the generator reads the class-level guards,@UseRouteConfigand@UseMiddleware, then each route method’s annotation, guards and parameters. - It classifies each parameter (path, query, header, body, form, service, context, request) and emits the code that extracts and converts it.
- It emits a constant
RouteConfigmerge chain, the call to your method and the response conversion. source_gen’s combining builder writes the result intoyour_file.g.dart, which your file includes withpart 'your_file.g.dart';.
What this buys you:
- No runtime cost for routing decisions: everything is decided at build time.
- Readable output. Open the
.g.dartfile to see exactly how a request reaches your method. - Build-time errors for parameters the generator can’t classify.
- Tooling can reuse it. gisila_doc reads the same annotations to produce OpenAPI specs.
What it costs:
- A build step. Use
watchwhile developing so output stays in sync. - Generated files to manage. Either commit
.g.dartfiles (simple deploys, reviewable diffs) or generate them in CI before building; be consistent. - Signature rules to learn: see parameter binding rules.
Example
Section titled “Example”import 'package:gisila/gisila.dart';
part 'health_controller.g.dart';
@Controller('/health')class HealthController { @Get('/') Future<Map<String, Object?>> check() async => {'status': 'ok'};}dart run build_runner build --delete-conflicting-outputsapp.registerController(attacher: HealthController().attachToApp);