Guards API - Flint Dart

API Documentation

Complete reference for Flint Dart framework classes and methods. Use the sidebar to jump to a module.

Flint

Application root that wires routes, middleware, static assets, WebSockets, and server lifecycle.

A Flint instance is the entry point for your server. It registers HTTP routes, WebSocket endpoints, mounts route groups, and controls server startup with optional hot reload and auto-connect services.

Flint({String rootPath = "lib", String? viewPath, bool autoConnectDb = true, bool autoConnectMail = true, bool withDefaultMiddleware = true, bool enableSwaggerDocs = false})
Create a new app instance with optional defaults for middleware, DB, mail, and Swagger docs.
RouteBuilder get/post/put/delete/patch(String path, Object handler)
Register HTTP routes using Context handlers (or legacy handlers) with optional route-level middleware via RouteBuilder.useMiddleware.
RouteBuilder route(String method, String path, Handler handler)
Register a custom HTTP method (e.g. OPTIONS, HEAD).
void use(Middleware middleware)
Register global middleware executed for every request.
void mount(String prefix, void Function(Flint) callback, {List<Middleware> middlewares = const []})
Mount a sub-app under a URL prefix with optional scoped middleware.
void routes(RouteGroup group, {List<RouteGroup> children = const []})
Register a route group and optional nested groups with composed prefixes and middleware.
void websocket(String path, Object handler, {List<Middleware> middlewares = const []})
Register a WebSocket endpoint with Context handler support and optional route middleware.
void static(String urlPrefix, String directoryPath)
Serve static files from a directory under a URL prefix.
Future<void> listen({int? port, bool hotReload = true})
Start the HTTP + WebSocket server, optionally with hot reload.

Example

import 'package:flint_dart/flint_dart.dart';

void main() {
  final app = Flint(enableSwaggerDocs: true);

	  app.get('/health', (Context ctx) async {
	    return ctx.res?.json({'status': 'ok'});
	  });

  app.listen(port: 3030, hotReload: true);
}

Request

HTTP request wrapper with parsing, auth, session, and file helpers.

Property Type Description
method String HTTP method (GET, POST, PUT, ...).
path String Request path (no query string).
uri Uri Full request URI.
params Map<String, String> Route params matched by the router.
query Map<String, String> Query parameters from the URL.
headers Map<String, String> Request headers as a normalized map.
ipAddress String Client IP address if available.
bearerToken String? Bearer token from the Authorization header.
sessionId String? Session id from the FLINTSESSID cookie.
Method Returns Notes
param(String key) String? Read a route parameter by name.
queryParam(String key) String? Read a query parameter by name.
input(String key) String? Alias for route or query param lookup.
body() Future<String> Read the raw request body.
json() Future<Map<String, dynamic>> Parse JSON request bodies (throws on invalid JSON).
form() Future<Map<String, String>> Parse URL-encoded or multipart form data.
file(String fieldName) Future<UploadedFile?> Access a single uploaded file.
files(String fieldName) Future<List<UploadedFile?>> Access multiple uploads for a field.
allFiles() Future<Map<String, UploadedFile>> Return all uploaded files.
storeFile(String fieldName, {String directory, String? filename}) Future<String?> Persist an uploaded file and return the saved path.
storeFiles(String fieldName, {String directory}) Future<List<String>> Persist multiple uploads and return their paths.
validate(Map<String, String> rules) Future<Map<String, dynamic>> Validate JSON body with rule strings.
validateForm(Map<String, String> rules) Future<Map<String, String>> Validate form fields with rule strings.
startSession(Map<String, dynamic> data, {Duration? ttl}) Future<String> Create a session and set the session cookie.
updateSession(Map<String, dynamic> updates, {Duration? ttl}) Future<String?> Merge updates and create a new session id.
destroySession() Future<void> Destroy the current session and clear the cookie.
get user Future<Map<String, dynamic>?> Resolve the authenticated user from JWT or session.
isAuthenticated bool True if a user payload has been resolved.
requireUser() Map<String, dynamic> Return the user or throw if unauthenticated.

Example

app.post('/upload', (Context ctx) async {
  final body = await ctx.req.validate({'title': 'required|string'});
  final image = await ctx.req.file('image');

  if (image == null) {
    return ctx.res.status(422).json({'error': 'image is required'});
  }

  final path = await ctx.req.storeFile('image');
  return ctx.res.json({'title': body['title'], 'path': path});
});

Response

Response helper for JSON, HTML, files, views, and FlintUI rendering.

Method Returns Notes
send(String body, {int? status, String contentType = 'text/plain'}) Response Send plain text or custom content.
json(dynamic data, {int? status}) Future<Response> Send JSON data with automatic serialization.
respond(dynamic data, {int? status, RespondType? type}) Future<Response> Send a response with type inference (JSON, HTML, plain text, FlintUI).
status(int code) Response Set the HTTP status code (chainable).
redirect(String location, {int status = 302}) Response Redirect the client to a new location.
back({String fallback = '/', int status = 302}) Response Redirect to the Referer header, or to fallback when missing.
withFlash(String key, String message) Response Set a one-request flash message for templates.
withSuccess(String message) / withError(String message) Response Convenience wrappers for success/error flash messages.
sendStatus(int code) Response Send a standard status message for a status code.
view(String templateName, {Map<String, dynamic>? data}) Future<Response> Render a template from lib/views.
render(FlintWidget widget, {String? title, int? status, bool includePreview = false}) Response Render FlintUI widgets as HTML.
renderEmail(ViewMailable mailable, {bool includePreview = true}) Response Render a Flint email template.
streamFile(File file, {int start = 0, int? end}) Future<void> Stream a file to the client (supports byte ranges).
setCookie(String name, String value, {DateTime? expires, int? maxAge, String path = '/', bool httpOnly = true, bool secure = false, String sameSite = 'Lax'}) Response Set a cookie header.
clearCookie(String name, {String path = '/'}) Response Remove a cookie by setting an expired value.
close() Future<void> Close the underlying response stream.

Example

app.get('/profile', (Context ctx) async {
  final user = await ctx.req.user;
  if (user == null) {
    return ctx.res.status(401).json({'error': 'Unauthorized'});
  }
  return ctx.res.view('profile.show', data: {'user': user});
});

Direct Return Serialization

class UserDto {
  final int id;
  final String email;
  UserDto(this.id, this.email);

  Map<String, dynamic> toJson() => {'id': id, 'email': email};
}

app.get('/me', (Context ctx) async {
  return UserDto(1, 'ada@example.com'); // serialized automatically
});

Flash + Back Redirect

app.post('/profile', (Context ctx) async {
  final data = await ctx.req.validate({'name': 'required|string|min:2'});
  // ... save data
  return ctx.res
      ?.withSuccess('Profile updated successfully.')
      .back(fallback: '/profile');
});

Router

Matches incoming requests to handlers and supports route params, regex, and wildcards.

Flint routes are defined on the Flint app, which internally uses Router and RouteBuilder for matching and middleware composition.

void add(String method, String path, Handler handler, {List<Middleware> middlewares = const []})
Low-level route registration used by the framework and builders.
RouteBuilder get/post/put/delete/patch(...)
Use the app-level helpers to register routes and attach middleware.
Path params: /users/:id or /users/:id(\d+)
Named params can include optional regex patterns for validation.
Wildcard: /public/*
Match all paths under a prefix (used by static file routing).

Example

app.get('/users/:id(\\d+)', (Context ctx) async {
  final id = ctx.req.params['id'];
  return ctx.res?.json({'id': id});
});

Middleware

Wrap handlers to add auth, logging, validation, or transforms.

A middleware implements Middleware.handle and returns a new handler that can short-circuit or augment the request/response pipeline.

abstract class Middleware { Handler handle(Handler next); }
Implement this contract to create custom middleware.
void use(Middleware middleware)
Register a global middleware on the app.
RouteBuilder.useMiddleware(Middleware middleware)
Attach middleware to a specific route.
void websocket(String path, Object handler, {List<Middleware> middlewares = const []})
Attach middleware directly to a WebSocket route via the middlewares argument.
Built-ins: ExceptionMiddleware, CorsMiddleware, LoggerMiddleware, StaticFileMiddleware, CookieSessionMiddleware
Drop-in middleware shipped with Flint.

Declare Middleware

class AuthGuard extends Middleware {
  @override
  Handler handle(Handler next) {
    return (Context ctx) async {
      final token = ctx.req.headers['authorization'];
      if (token == null || token.isEmpty) {
        if (ctx.res != null) {
          return ctx.res!.status(401).json({'error': 'Unauthorized'});
        }
        return null;
      }
      return await next(ctx);
    };
  }
}

Use on HTTP

app.get('/private', (Context ctx) async => ctx.res?.send('ok'))
  .useMiddleware(AuthGuard());

app.use(AuthGuard()); // global

Use on WebSocket

app.websocket(
  '/chat',
  (Context ctx) {
    final socket = ctx.socket;
    if (socket == null) return;
    socket.on('ping', (_) => socket.emit('pong', {'ok': true}));
  },
  middlewares: [AuthGuard()],
);

Model

Base ORM model for CRUD, relations, and typed attribute access.

Property Type Description
table Table Schema definition for the model.
primaryKey String Primary key column (defaults to id).
conceal List<String> Fields hidden from toMap().
qb QueryBuilder Query builder scoped to the model table.
Future<T?> find(dynamic id)
Find a model by its primary key.
Future<T?> firstWhere(String key, dynamic value)
Return the first record matching a field condition.
Future<List<T>> get()
Fetch all rows using the current query builder state.
T withRelation(String name, {List<String>? columns})
Eager load a relation by name.
Future<T> load(String relation, {List<String>? columns})
Load a relation on a single model instance.
Map<String, dynamic> toMap()
Return a sanitized map of attributes.

Example

class User extends Model {
  User() : super(() => User());

  @override
  Table get table => Table(
    name: 'users',
    columns: [
      Column(name: 'email', type: ColumnType.string, isUnique: true),
      Column(name: 'name', type: ColumnType.string),
    ],
  );
}

final user = await User().find('uuid');

Query Builder

Chainable SQL builder for filtering, sorting, aggregates, and pagination.

Method Returns Notes
select([List<String>? fields]) QueryBuilder Select specific columns (defaults to *).
where(String field, String operator, dynamic value) QueryBuilder Add a WHERE clause with an operator.
whereIn/whereNotIn(String field, List<dynamic> values) QueryBuilder Filter against a list of values.
whereLike/whereContains/whereStartsWith/whereEndsWith(...) QueryBuilder Filter using LIKE helpers.
orWhere(String field, String operator, dynamic value) QueryBuilder Append an OR condition.
orderBy(String field, [String direction = 'ASC']) QueryBuilder Sort results by a column.
groupBy(String field) QueryBuilder Group results by a column.
limit(int value), offset(int value) QueryBuilder Limit result size and offset.
get() Future<List<Map<String, dynamic>>> Execute the query and return all rows.
first() Future<Map<String, dynamic>?> Execute the query and return the first row.
paginate(int page, [int perPage = 15]) Future<Map<String, dynamic>> Paginate results with totals.
insert(Map<String, dynamic> data) Future<void> Insert a new row (auto-generates UUIDs for string IDs).
update(Map<String, dynamic> data) Future<void> Update rows matching the current WHERE clause.
delete() Future<void> Delete rows matching the current WHERE clause.
count() Future<int> Count rows matching the current query.
sum(String column), avg(String column) Future<double?> Aggregate numeric columns.
min(String column), max(String column) Future<dynamic> Return min/max values for a column.

Example

final qb = QueryBuilder(table: 'users');

final page = await qb
  .where('status', '=', 'active')
  .orderBy('created_at', 'DESC')
  .paginate(1, 20);

return ctx.res?.json(page);

Migration

Schema synchronization driven by registered table definitions.

Flint migrations are executed via the CLI. The migrator loads table definitions from lib/config/table_registry.dart and generates CREATE/ALTER statements.

flint migrate
Create or update tables based on the registered schema.
flint migrate --force
Drop and recreate tables that already exist.
flint migrate --drop
Drop all tables before migrating (destructive).

Schema

Define tables, columns, indexes, and foreign keys.

Table({required String name, required List<Column> columns})
Define a table schema. An id column is added if none is provided.
Column({required String name, required ColumnType type, ...})
Define a column, optionally setting primary key, uniqueness, defaults, or nullability.
Index({required String name, required List<String> columns, bool isUnique = false})
Define indexes for faster lookups.
ForeignKey({required String column, required String referenceTable, required String referenceColumn, required ForeignKeyAction onDelete, required ForeignKeyAction onUpdate})
Declare foreign key constraints.

Example

final usersTable = Table(
  name: 'users',
  columns: [
    Column(name: 'email', type: ColumnType.string, isUnique: true),
    Column(name: 'name', type: ColumnType.string),
    Column(name: 'created_at', type: ColumnType.timestamp, defaultValue: Default.currentTimestamp()),
  ],
  indexes: [
    Index(name: 'users_email_idx', columns: ['email'], isUnique: true),
  ],
);

Auth

User registration, login, JWT verification, and OAuth helpers.

Future<Map<String, dynamic>> Auth.login(String email, String password, {String? throttleKey})
Authenticate a user and return a JWT token plus user data. Supports optional throttle key when lockout is enabled.
Future<Map<String, dynamic>> Auth.loginWithTokens(String email, String password, {String? throttleKey, String? ipAddress, String? userAgent, String? deviceName})
Issue access token and optional refresh token (when AUTH_ENABLE_REFRESH_TOKENS=true).
Future<Map<String, dynamic>?> Auth.refreshAccessToken(String refreshToken, {bool rotateRefreshToken = true, String? ipAddress, String? userAgent, String? deviceName})
Exchange a refresh token for a new access token and optional rotated refresh token.
Future<void> Auth.revokeRefreshToken(String refreshToken)
Revoke a single refresh token.
Future<void> Auth.revokeAllRefreshTokensForUser(Object? userId)
Revoke all refresh tokens for a specific user.
Future<Map<String, dynamic>> Auth.register({required String email, required String password, String? name, Map<String, dynamic>? additionalData})
Create a new user record and return the sanitized user data.
Map<String, dynamic>? Auth.verifyToken(String token)
Verify a JWT and return the payload.
Auth.loginWithGoogle/GitHub/Facebook/Apple(...)
Authenticate with OAuth providers and receive provider user data.
Future<Map<String, dynamic>> Auth.saveProviderUser({required Map<String, dynamic> providerUserData, Map<String, dynamic>? additionalData})
Persist a provider user profile into the auth table.
Future<String?> Auth.generatePasswordResetToken(String email)
Generate a password reset token and store it securely.
Future<bool> Auth.resetPassword({required String token, required String newPassword})
Reset a password using a reset token.
Future<String?> Auth.generateEmailVerificationToken(String email)
Create a verification token for email confirmation.

Example

app.post('/login', (Context ctx) async {
  final data = await ctx.req.validate({
    'email': 'required|email',
    'password': 'required|string',
  });

  final result = await Auth.loginWithTokens(
    data['email'],
    data['password'],
    throttleKey: ctx.req.ipAddress,
    ipAddress: ctx.req.ipAddress,
    userAgent: ctx.req.headers['user-agent'],
    deviceName: 'web',
  );
  return ctx.res.json(result); // { user, accessToken, token, refreshToken? }
});

app.post('/refresh', (Context ctx) async {
  final data = await ctx.req.validate({
    'refreshToken': 'required|string',
  });

  final next = await Auth.refreshAccessToken(
    data['refreshToken'],
    rotateRefreshToken: true,
    ipAddress: ctx.req.ipAddress,
    userAgent: ctx.req.headers['user-agent'],
  );

  if (next == null) {
    return ctx.res.status(401).json({'error': 'Invalid refresh token'});
  }

  return ctx.res.json(next);
});

Auth Guards

Protect routes with middleware and request auth helpers.

Flint does not require a separate guard system. Use middleware and ctx.req.user to enforce access.

Example

class AuthGuard extends Middleware {
  @override
  Handler handle(Handler next) {
    return (Context ctx) async {
      final user = await ctx.req.user;
      if (user == null) {
        return ctx.res.status(401).json({'error': 'Unauthorized'});
      }
      return next(ctx);
    };
  }
}

app.get('/dashboard', (Context ctx) async => ctx.res.send('ok'))
  .useMiddleware(AuthGuard());

Auth Providers

OAuth URL generation and provider metadata.

String AuthService.getGoogleAuthUrl({required String callbackUrl})
Build a Google OAuth URL with PKCE support.
String AuthService.getGitHubAuthUrl({required String callbackUrl})
Build a GitHub OAuth authorization URL.
String AuthService.getFacebookAuthUrl({required String callbackUrl})
Build a Facebook OAuth authorization URL.
String AuthService.getAppleAuthUrl({required String callbackUrl})
Build an Apple Sign In URL.
Map<String, dynamic> AuthService.getAvailableProviders()
Return configured providers and redirect base info.

Example

app.get('/auth/google', (Context ctx) async {
  final url = AuthService.getGoogleAuthUrl(
    callbackUrl: 'http://localhost:3030/auth/google/callback',
  );
  return ctx.res.redirect(url);
});

Components

FlintUI widgets for server-rendered UI and email templates.

FlintUI widgets produce HTML and plain text output. Render them with ctx.res.render() or use them inside email templates via ViewMailable.

Text, Container, Row, Column, Button, Image, Head
Core widgets for layout, typography, and content.
FlintComponent
Stateful component base class that renders using FlintWidgets.

Example

app.get('/welcome', (Context ctx) async {
  return ctx.res.render(
    Container(
      padding: EdgeInsets.all(24),
      children: [
        Text('Welcome to Flint', fontSize: 28),
        Button(text: 'Get Started', url: '/guides'),
      ],
    ),
  );
});

Layout

Row/column layout primitives and spacing utilities.

Use Row and Column to compose layouts. Most widgets accept padding/margin via EdgeInsets and borders via BoxBorder.

Row({required List<FlintWidget> children, double gap = 16.0, List<int> columnWidths = const []})
Horizontal layout optimized for consistent HTML/email rendering.
Column({required List<FlintWidget> children, double gap = 5.0})
Vertical layout with adjustable spacing between children.
EdgeInsets.all/only/symmetric(...)
Apply consistent padding and margin.

Forms

Form parsing, file uploads, and validation helpers.

Future<Map<String, String>> ctx.req.form()
Parse application/x-www-form-urlencoded or multipart/form-data.
Future<UploadedFile?> ctx.req.file(String fieldName)
Access a single file upload from multipart form data.
Future<Map<String, String>> ctx.req.validateForm(Map<String, String> rules)
Validate form fields using the validator rules.

Example

app.post('/contact', (Context ctx) async {
  final form = await ctx.req.validateForm({
    'name': 'required|string',
    'email': 'required|email',
  });

  return ctx.res.json({'received': form});
});

Cache

Simple cache stores for memory or filesystem-backed caching.

abstract class CacheStore { set/get/remove/clear }
Contract implemented by cache stores.
MemoryCacheStore({int maxSize = 100})
In-memory cache with optional max size and TTL.
FileCacheStore({String? directory})
File-based cache persisted under cache/ by default.

Example

final cache = MemoryCacheStore();

await cache.set('greeting', 'hello', ttl: Duration(minutes: 10));
final value = await cache.get('greeting');

Session

Session management with memory, file, or DB storage.

SessionManager()
Singleton session manager configured via SESSION_DRIVER.
Future<String> ctx.req.startSession(Map<String, dynamic> data, {Duration? ttl})
Create a session and set the FLINTSESSID cookie.
Future<Map<String, dynamic>?> ctx.req.session
Read session data for the current request.
Future<void> ctx.req.destroySession()
Destroy the current session and clear the cookie.

Example

app.post('/session', (Context ctx) async {
  await ctx.req.startSession({'id': 'user-1', 'role': 'admin'});
  return ctx.res.json({'ok': true});
});

Storage

Utility for saving, updating, and deleting uploaded files.

Future<String> Storage.create(UploadedFile file, {String? subdirectory})
Save a file under public/ and return a public URL.
Future<void> Storage.delete(String fileUrl)
Delete a file by its public URL.
Future<String> Storage.update(String oldFileUrl, UploadedFile newFile, {String? subdirectory})
Replace a file and return the new URL.

Mail

Send or queue email via SMTP.

Mail.setup({required MailProvider provider, required String host, required int port, required String username, required String password, required String fromAddress, String fromName = 'Flint Dart', bool useSSL = false, bool useTLS = true})
Configure SMTP settings once at startup.
Mail().to(...).subject(...).text(...).sendMail()
Send mail immediately.
Mail().html(...).queue()
Send mail in a background isolate.

Example

Mail.setup(
  provider: MailProvider.custom,
  host: 'smtp.example.com',
  port: 587,
  username: 'user',
  password: 'secret',
  fromAddress: 'noreply@example.com',
);

await Mail()
  .to('user@example.com')
  .subject('Welcome')
  .text('Thanks for signing up')
  .sendMail();

Validation

Rule-based input validation for JSON and form data.

Future<void> Validator.validate(Map<String, dynamic> data, Map<String, String> rules, {Map<String, String>? messages})
Validate a data map and throw ValidationException on failure.
Future<Map<String, dynamic>> ctx.req.validate(Map<String, String> rules)
Validate JSON body and return the parsed map.
Future<Map<String, String>> ctx.req.validateForm(Map<String, String> rules)
Validate form data and return the parsed map.

Example

final data = await ctx.req.validate({
  'email': 'required|email',
  'password': 'required|string|min:8',
});

REST API Example

Example user endpoints using QueryBuilder.paginate() and validation helpers:

GET /api/users
Get all users with pagination
Parameter Type Required Description
page int No Page number (default: 1)
per_page int No Items per page (default: 15)

Response:

{
  "data": [
    {
      "id": "3a4b8e1f",
      "name": "John Doe",
      "email": "john@example.com",
      "created_at": "2024-01-15T10:30:00.000Z"
    }
  ],
  "current_page": 1,
  "per_page": 15,
  "total": 42,
  "last_page": 3
}
POST /api/users
Create a new user
Parameter Type Required Description
name string Yes User's full name
email string Yes User's email address (must be unique)
password string Yes User's password (min length defined in config)

Response (201 Created):

{
  "id": "a1b2c3d4",
  "name": "Jane Smith",
  "email": "jane@example.com",
  "created_at": "2024-01-15T11:00:00.000Z"
}