glimr/routing/annotation_parser
Annotation Parser
Controller files define routes via doc comment annotations
like /// @get "/users" above handler functions. This
parser reads those annotations and produces structured data
the route compiler uses to generate dispatch code. Keeping
route definitions as annotations means developers see the
URL right next to the handler — no separate routes file to
keep in sync.
Types
The route compiler needs to know each handler’s parameter
names and types to wire up the right arguments — a Request
gets the HTTP request, a Context gets the app context, and
anything else maps to a route param like :id. Tracking
both lets developers put parameters in any order they like.
pub type FunctionParam {
FunctionParam(name: String, param_type: String)
}
Constructors
-
FunctionParam(name: String, param_type: String)
Everything the route compiler needs from a single controller
file — the routes themselves, whether it exports a
middleware() function, and import flags. The import check
lets us catch a missing Context import early with a
helpful error instead of letting the Gleam compiler produce
a confusing “unknown type” message.
pub type ParseResult {
ParseResult(
routes: List(ParsedRoute),
has_context_import: Bool,
has_middleware_fn: Bool,
)
}
Constructors
-
ParseResult( routes: List(ParsedRoute), has_context_import: Bool, has_middleware_fn: Bool, )
A route can be either a real handler (ParsedRoute) or a redirect (ParsedRedirect). The route compiler turns these into match arms in the generated dispatch function — handlers call the controller function, while redirects emit a 303/308 response pointing at the target path.
pub type ParsedRoute {
ParsedRoute(
method: String,
path: String,
handler: String,
params: List(FunctionParam),
)
ParsedRedirect(from: String, to: String, status: Int)
}
Constructors
-
ParsedRoute( method: String, path: String, handler: String, params: List(FunctionParam), ) -
ParsedRedirect(from: String, to: String, status: Int)
Values
pub fn module_from_path(path: String) -> Result(String, Nil)
Glob gives us filesystem paths like
src/app/controllers/users.gleam but Gleam imports use
module paths like app/controllers/users. This strips the
src/ prefix and .gleam extension to bridge the gap.
pub fn parse(content: String) -> ParseResult
The main entry point — takes the raw source of a controller
file and returns everything the route compiler needs to
generate dispatch code. Routes come from the doc comments
above each handler function, and we detect whether the
controller exports a middleware() function so the compiler
can wrap handlers automatically.