Basics / Controllers

Controllers & FormRequests

Archery handles requests seamlessly through rich HttpRequest extensions and the highly capable FormRequest class, allowing you to access inputs, uploads, and generate intuitive HTTP responses.

Accessing the Request Context

In Archery, request handlers receive an HttpRequest object. The framework enhances this native Dart object with convenience extensions to inspect incoming data and craft outgoing responses.

Resolving Form Data

The FormRequest class acts as a single source of truth for body payload and query string data. It supports application/jsonapplication/x-www-form-urlencoded, and multipart/form-data.

You can access the form wrapper using the request.form() extension:

router.post('/profile/update', (request) async {
  final form = request.form();

  // Retrieve an individual input value (checks body then query)
  final email = await form.input('email');
  
  // Retrieve all parsed form data
  Map<String, dynamic> data = await form.all();
  
  // Retrieve strictly body fields or query parameters
  Map<String, dynamic> body = await form.body();
  Map<String, String> query = form.query;
});

Note: The request stream is automatically buffered on the first call to any async form() method, preventing issues where the request stream is listened to multiple times.

Retrieving the Authenticated User

If you are using Archery's authentication system, you can retrieve the current User directly from the request:

final user = await request.user;

if (user != null) {
  print("Welcome back, ${user.email}");
}

Generating Responses

Instead of manually crafting Dart HTTP responses, Archery’s HttpRequest extensions let you fluently return views, JSON payloads, plain text, and redirects.

Rendering Views

Return a beautifully templated HTML view using request.view(). To bind data to the view, simply provide it as a Dart Map.

router.get('/', (request) async {
  return request.view('dashboard.index', {
    'title': 'Project Dashboard',
    'stats': [12, 34, 56],
  });
});

The framework automatically injects session state and a robust CSRF token. The method will properly terminate the response context with strict security headers applied.

JSON Responses

Returning an API response is as easy as invoking request.json(). It will take a standard mapping or string, automatically encode it to JSON, and provide proper application/json content-type boundaries.

// Native encoding
return request.json({
  'status': 200,
  'message': 'Action successful'
});

// Working with domain models
return request.json(user.toJson());

Redirects

You can chain elegant redirects leveraging string helpers or context references.

// Redirect to absolute/relative paths
request.redirectTo(path: '/login');

// Redirect smartly back to the referring URL
request.redirectBack();

// Common destinations
request.redirectHome();
request.redirectToDashboard();

Flashing Session Messages

A common practice after a form submission is to redirect back to a given view, flashing a message or error for the user to consume during their next request cycle.

router.post('/post', (request) async {
  // Store a temporary success message
  request.flash(
    key: 'success', 
    message: 'Post created successfully.'
  );
  
  // Store an error 
  request.flash(
    key: 'title',
    message: 'The title field is required.',
    type: FlashMessageType.error,
  );

  return request.redirectBack();
});

Database Fast Failures

If you are incorporating Archery's built-in ORM, you can locate models right off the request wrapper. This provides beautiful fallback behaviors, like rendering your core 404 pages immediately when records are not found.

// Using ID
final post = await request.findOrFail<Post>(id: 42);

// Using a custom column
final user = await request.firstOrFail<User>(
  field: 'email', 
  value: 'jane@example.com'
);