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 data
POST - Create resources
PUT - Update resources
PATCH - Partial updates
DELETE - Remove resources
HEAD - Headers only
OPTIONS - CORS preflight

Handler 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

On this page