view method

Future<HttpResponse> view(
  1. String template, [
  2. ViewData? data
])

Renders an HTML template and writes it to the response.

This method:

  • resolves the configured TemplateEngine
  • loads the authenticated user into session state
  • reuses or generates a CSRF token
  • merges provided data with session and CSRF values
  • renders the template into HTML
  • configures response headers and content length
  • stores a CSRF cookie when a new token is generated

Parameters:

  • template: The template identifier to render.
  • data: Optional view data passed into the template.

Returns the active HttpResponse after writing and closing it.

Example:

return request.view('users.show', {
  'user': user,
  'pageTitle': 'User Profile',
});

Implementation

Future<HttpResponse> view(String template, [ViewData? data]) async {
  final container = App().container; // Cache reference
  final engine = container.make<TemplateEngine>();

  // 1. Parallelize data fetching if possible, but definitely cache user
  thisSession?.user = await Auth.user(this);

  // 2. Optimized Cookie Access: Search cookies ONCE
  Cookie? csrfCookie;
  Cookie? guestCookie;
  for (var c in cookies) {
    if (c.name == 'archery_csrf_token') csrfCookie = c;
    if (c.name == 'archery_guest_session') guestCookie = c;
    if (csrfCookie != null && guestCookie != null) break;
  }

  String token;
  bool isNewToken = false;

  if (data?.containsKey('csrf_token') ?? false) {
    token = data!['csrf_token'];
  } else if (csrfCookie != null) {
    token = csrfCookie.value;
  } else {
    token = App.generateKey();
    isNewToken = true;
  }

  try {
    // 3. Merging data: Use a single map spread
    final viewData = {
      ...?data,
      "session": thisSession?.toJson(),
      'csrf_token': token
    };

    final html = await engine.render(template, viewData);
    final bodyBytes = utf8.encode(html);

    // 4. Batch Header Setting
    response.headers.contentLength = bodyBytes.length;
    _viewHeaders.forEach(response.headers.set);
    response.persistentConnection = true;

    if (isNewToken) {
      response.cookies.add(
          Cookie('archery_csrf_token', token)
            ..httpOnly = true ..secure = true
            ..sameSite = SameSite.lax ..path = '/'
      );
    }

    // 5. Direct lookup for sessions list
    final sessions = App().tryMake<List<Session>>();
    if (sessions != null && guestCookie != null) {
      final session = sessions.firstWhereOrNull((s) => s.token == guestCookie!.value);
      if (session != null) session.csrf = token;
    }

    return response
      ..add(bodyBytes) // Use .add() for bytes to bypass re-encoding strings
      ..close();

  } catch (e) {
    return response
      ..write("error") // Use .add() for bytes to bypass re-encoding strings
      ..close();
  }
}