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.

Search Document