Khadem Routing System
Clean, modular HTTP routing with parameter support, middleware, and route groups.
Basic Routes
dart
// Basic HTTP method routes
server.get('/users', (req, res) async {
final users = await User.all();
res.sendJson({'users': users});
});
server.post('/users', (req, res) async {
final data = await req.body;
final user = await User.create(data);
res.statusCode(201).sendJson({'user': user});
});
server.put('/users/:id', (req, res) async {
final userId = req.param('id');
final data = await req.body;
final user = await User.find(userId).update(data);
res.sendJson({'user': user});
});
server.delete('/users/:id', (req, res) async {
final userId = req.param('id');
await User.find(userId).delete();
res.statusCode(204).empty();
});
Supported Methods
GET
- Retrieve dataPOST
- Create resourcesPUT
- Update resourcesPATCH
- Partial updatesDELETE
- Remove resourcesHEAD
- Headers onlyOPTIONS
- CORS preflightHandler Signature
dart
Future Function(Request, Response)
Async handlers with Request/Response objects
Route Parameters
dart
// Route parameters with :param syntax
server.get('/users/:id', (req, res) async {
final userId = req.param('id');
final user = await User.find(userId);
if (user == null) {
return res.statusCode(404).sendJson({
'error': 'User not found'
});
}
res.sendJson({'user': user});
});
// Multiple parameters
server.get('/posts/:category/:slug', (req, res) async {
final category = req.param('category');
final slug = req.param('slug');
final post = await Post.where('category', category)
.where('slug', slug)
.first();
res.sendJson({'post': post});
});
// Optional query parameters
server.get('/search', (req, res) async {
final query = req.query['q'] ?? '';
final page = int.tryParse(req.query['page'] ?? '1') ?? 1;
final limit = int.tryParse(req.query['limit'] ?? '10') ?? 10;
final results = await Search.query(query, page: page, limit: limit);
res.sendJson({'results': results});
});
Parameter Features
:param
syntax for named parameters- Automatic parameter extraction
- Type-safe parameter access
- Regex-based matching
Route Groups
dart
// Route groups with shared prefix and middleware
server.group(
prefix: '/api/v1',
middleware: [AuthMiddleware(), ApiMiddleware()],
routes: (router) {
router.get('/users', UserController.index);
router.post('/users', UserController.store);
router.get('/users/:id', UserController.show);
router.put('/users/:id', UserController.update);
router.delete('/users/:id', UserController.destroy);
// Nested groups
router.group(
prefix: '/admin',
middleware: [AdminMiddleware()],
routes: (adminRouter) {
adminRouter.get('/stats', AdminController.stats);
adminRouter.post('/users/:id/ban', AdminController.banUser);
}
);
}
);
Group Benefits
- Shared URL prefixes
- Common middleware
- Better organization
- Nested groups supported
Generated Routes
text
Generated routes:
GET /api/v1/users
POST /api/v1/users
GET /api/v1/users/:id
PUT /api/v1/users/:id
DELETE /api/v1/users/:id
GET /api/v1/admin/stats
POST /api/v1/admin/users/:id/ban
Middleware Integration
dart
// Global middleware (all routes)
server.useMiddlewares([
LoggingMiddleware(),
CorsMiddleware(),
RateLimitMiddleware(),
]);
// Group middleware
server.group(
prefix: '/admin',
middleware: [AuthMiddleware(), AdminMiddleware()],
routes: (router) {
router.get('/dashboard', AdminController.dashboard);
}
);
// Route-specific middleware
server.get('/public', PublicController.index);
server.get('/protected', ProtectedController.index,
middleware: [AuthMiddleware()]);
server.get('/admin-only', AdminController.index,
middleware: [AuthMiddleware(), AdminMiddleware()]);
Middleware Levels
Global
All routes
Group
Group routes
Route
Specific route
Static File Serving
dart
// Serve static files from public directory
server.serveStatic('public');
// Custom static directory
server.serveStatic('assets');
// Now these URLs work automatically:
// GET /css/style.css → public/css/style.css
// GET /images/logo.png → public/images/logo.png
// GET /js/app.js → public/js/app.js
Static Serving Features
- Automatic file type detection
- Directory browsing disabled
- Configurable root directory
- Efficient caching headers
Advanced Patterns
Query Parameters
dart
server.get('/search', (req, res) async {
// Query parameters
final query = req.query['q'];
final page = req.query['page'];
final sort = req.query['sort'];
// Form data (for POST/PUT)
final formData = await req.body;
final name = formData['name'];
final email = formData['email'];
res.sendJson({
'query': query,
'page': page,
'sort': sort,
'form': {'name': name, 'email': email}
});
});
Access URL query strings and form data
Response Types
dart
// JSON response
res.sendJson({'message': 'Hello World'});
// HTML response
await res.view('welcome');
// File download
await res.download('files/report.pdf');
// Stream response
await res.stream<String>(
Stream.periodic(Duration(seconds: 1), (i) => 'Line $i
').take(10)
);
// Custom status
res.statusCode(201).sendJson({'created': true});
// Empty response
res.statusCode(204).empty();
JSON, HTML, files, and streaming responses
Complete API Example
dart
import 'package:khadem/khadem_dart.dart';
void registerRoutes(Server server) {
// Global middleware
server.useMiddlewares([
LoggingMiddleware(),
CorsMiddleware(),
RateLimitMiddleware(),
]);
// Public routes
server.group(
prefix: '/api/v1',
routes: (router) {
router.get('/health', (req, res) async {
res.sendJson({
'status': 'ok',
'timestamp': DateTime.now().toIso8601String()
});
});
}
);
// User routes (authenticated)
server.group(
prefix: '/api/v1/users',
middleware: [AuthMiddleware()],
routes: (router) {
router.get('', UserController.index);
router.post('', UserController.store);
router.get('/:id', UserController.show);
router.put('/:id', UserController.update);
router.delete('/:id', UserController.destroy);
// User relationships
router.get('/:id/posts', UserController.posts);
router.get('/:id/followers', UserController.followers);
}
);
// Post routes
server.group(
prefix: '/api/v1/posts',
middleware: [AuthMiddleware()],
routes: (router) {
router.get('', PostController.index);
router.post('', PostController.store);
router.get('/:id', PostController.show);
router.put('/:id', PostController.update);
router.delete('/:id', PostController.destroy);
// Comments
router.get('/:id/comments', PostController.comments);
router.post('/:id/comments', PostController.addComment);
}
);
// Admin routes
server.group(
prefix: '/api/v1/admin',
middleware: [AuthMiddleware(), AdminMiddleware()],
routes: (router) {
router.get('/dashboard', AdminController.dashboard);
router.get('/stats', AdminController.stats);
router.get('/users', AdminController.users);
router.post('/users/:id/ban', AdminController.banUser);
}
);
// Static files
server.serveStatic('public');
}
// Start server
Future<void> main() async {
final server = Server();
registerRoutes(server);
await server.start(port: 8080);
}
Best Practices
✅ Recommendations
- Use route groups for logical organization
- Apply middleware at the appropriate level
- Use descriptive parameter names
- Keep handlers focused and testable
- Validate input parameters
❌ Avoid
- Don't put business logic in route handlers
- Don't create deeply nested groups
- Don't use generic parameter names
- Don't skip input validation