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.
RouteBuilder.useMiddleware.OPTIONS, HEAD).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.
/users/:id or /users/:id(\d+)/public/*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.
middlewares argument.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. |
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.
Schema
Define tables, columns, indexes, and foreign keys.
id column is added if none is provided.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.
AUTH_ENABLE_REFRESH_TOKENS=true).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.
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.
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.
Forms
Form parsing, file uploads, and validation helpers.
application/x-www-form-urlencoded or multipart/form-data.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.
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.
SESSION_DRIVER.FLINTSESSID 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.
public/ and return a public URL.Send or queue email via SMTP.
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.
ValidationException on failure.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:
| 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
}
| 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"
}