Documentation Index
Fetch the complete documentation index at: https://mintlify.com/khode-io/nest-dart/llms.txt
Use this file to discover all available pages before exploring further.
Middleware Patterns
Nest Frog provides middleware integration for Dart Frog applications, enabling dependency injection and module-based architecture in your backend routes.The nestFrogMiddleware
The core middleware initializes the application container and makes services available to all routes:import 'package:dart_frog/dart_frog.dart';
import 'package:nest_frog/nest_frog.dart';
Handler middleware(Handler handler) {
return handler
.use(nestFrogMiddleware(AppModule()));
}
How It Works
Frompackages/nest_frog/lib/src/middleware.dart:7-18:
Middleware nestFrogMiddleware(Module appModule) {
return (handler) {
return (context) async {
// Initialize container if not already done
if (!Modular.isInitialized) {
await Modular.initialize(appModule);
}
return handler(context);
};
};
}
The middleware checks if the container is already initialized to avoid duplicate initialization on every request.
Basic Middleware Setup
In a Dart Frog project, createroutes/_middleware.dart:
import 'package:dart_frog/dart_frog.dart';
import 'package:nest_frog/nest_frog.dart';
import 'package:your_app/app_module.dart';
Handler middleware(Handler handler) {
return handler
.use(nestFrogMiddleware(AppModule()));
}
AppModule available to your routes:
// routes/users/index.dart
import 'package:dart_frog/dart_frog.dart';
import 'package:nest_frog/nest_frog.dart';
import 'package:your_app/services/user_service.dart';
Future<Response> onRequest(RequestContext context) async {
final userService = Modular.get<UserService>();
final users = await userService.getAllUsers();
return Response.json(body: users);
}
Middleware Composition
Combine nest middleware with other Dart Frog middleware:import 'package:dart_frog/dart_frog.dart';
import 'package:nest_frog/nest_frog.dart';
final message = 'Welcome to Dart Frog with NestJS-like Modules!';
Handler middleware(Handler handler) {
return handler
.use(nestFrogMiddleware(AppModule()))
.use(provider<String>((context) => message))
.use(loggingMiddleware())
.use(corsMiddleware());
}
Middleware loggingMiddleware() {
return (handler) {
return (context) async {
final stopwatch = Stopwatch()..start();
final response = await handler(context);
print('Request processed in ${stopwatch.elapsedMilliseconds}ms');
return response;
};
};
}
Middleware corsMiddleware() {
return (handler) {
return (context) async {
final response = await handler(context);
return response.copyWith(
headers: {
...response.headers,
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
},
);
};
};
}
Middleware order matters! The nest middleware should typically be one of the first middleware in the chain to ensure the container is initialized before other middleware try to access services.
Context-Based Service Access
UseModular.of(context) for context-aware service resolution:
import 'package:dart_frog/dart_frog.dart';
import 'package:nest_frog/nest_frog.dart';
Future<Response> onRequest(RequestContext context) async {
// Context-based access
final userService = Modular.of(context).get<UserService>();
// Falls back to container if not in context
final users = await userService.getAllUsers();
return Response.json(body: users);
}
ModularContext class from packages/nest_frog/lib/src/nest_frog.dart:60-88:
class ModularContext {
final RequestContext _context;
ModularContext._(this._context);
/// Get a service from the request context
T get<T extends Object>() {
try {
return _context.read<T>();
} catch (e) {
// Fallback to container if not in context
return Modular.get<T>();
}
}
/// Check if a service is available in the context
bool has<T extends Object>() {
try {
_context.read<T>();
return true;
} catch (e) {
return false;
}
}
}
Creating Custom Middleware
Authentication Middleware
import 'package:dart_frog/dart_frog.dart';
import 'package:nest_frog/nest_frog.dart';
import 'package:your_app/services/auth_service.dart';
Middleware authMiddleware() {
return (handler) {
return (context) async {
final authService = Modular.get<AuthService>();
final token = context.request.headers['authorization'];
if (token == null) {
return Response.json(
statusCode: 401,
body: {'error': 'Unauthorized'},
);
}
final user = await authService.validateToken(token);
if (user == null) {
return Response.json(
statusCode: 401,
body: {'error': 'Invalid token'},
);
}
// Provide user to downstream handlers
return handler(
context.provide<User>(() => user),
);
};
};
}
Request Validation Middleware
Middleware validationMiddleware() {
return (handler) {
return (context) async {
final request = context.request;
// Only validate POST/PUT requests
if (request.method != HttpMethod.post &&
request.method != HttpMethod.put) {
return handler(context);
}
final contentType = request.headers['content-type'];
if (contentType != 'application/json') {
return Response.json(
statusCode: 400,
body: {'error': 'Content-Type must be application/json'},
);
}
try {
final body = await request.json();
return handler(
context.provide<Map<String, dynamic>>(() => body),
);
} catch (e) {
return Response.json(
statusCode: 400,
body: {'error': 'Invalid JSON body'},
);
}
};
};
}
Rate Limiting Middleware
import 'package:dart_frog/dart_frog.dart';
import 'package:nest_frog/nest_frog.dart';
import 'package:your_app/services/rate_limiter_service.dart';
Middleware rateLimitMiddleware({int maxRequests = 100, Duration window = const Duration(minutes: 1)}) {
return (handler) {
return (context) async {
final rateLimiter = Modular.get<RateLimiterService>();
final ip = context.request.headers['x-forwarded-for'] ??
context.request.headers['x-real-ip'] ??
'unknown';
final isAllowed = await rateLimiter.checkLimit(
ip,
maxRequests: maxRequests,
window: window,
);
if (!isAllowed) {
return Response.json(
statusCode: 429,
body: {'error': 'Too many requests'},
headers: {
'Retry-After': window.inSeconds.toString(),
},
);
}
return handler(context);
};
};
}
Route-Specific Middleware
Apply middleware to specific route groups:// routes/api/_middleware.dart
import 'package:dart_frog/dart_frog.dart';
import 'package:nest_frog/nest_frog.dart';
Handler middleware(Handler handler) {
return handler
.use(authMiddleware())
.use(validationMiddleware());
}
// routes/public/_middleware.dart
import 'package:dart_frog/dart_frog.dart';
Handler middleware(Handler handler) {
return handler
.use(corsMiddleware())
.use(loggingMiddleware());
}
Dart Frog applies middleware hierarchically. Middleware in parent directories applies to all child routes.
Error Handling Middleware
Middleware errorHandlingMiddleware() {
return (handler) {
return (context) async {
try {
return await handler(context);
} on ValidationException catch (e) {
return Response.json(
statusCode: 400,
body: {'error': 'Validation failed', 'details': e.errors},
);
} on NotFoundException catch (e) {
return Response.json(
statusCode: 404,
body: {'error': e.message},
);
} on UnauthorizedException catch (e) {
return Response.json(
statusCode: 401,
body: {'error': e.message},
);
} catch (e, stackTrace) {
print('Unhandled error: $e');
print('Stack trace: $stackTrace');
return Response.json(
statusCode: 500,
body: {'error': 'Internal server error'},
);
}
};
};
}
Complete Middleware Stack Example
import 'package:dart_frog/dart_frog.dart';
import 'package:nest_frog/nest_frog.dart';
import 'package:your_app/app_module.dart';
Handler middleware(Handler handler) {
return handler
// 1. Initialize DI container (first!)
.use(nestFrogMiddleware(AppModule()))
// 2. Error handling (catch all errors)
.use(errorHandlingMiddleware())
// 3. Logging (track all requests)
.use(loggingMiddleware())
// 4. CORS (for browser clients)
.use(corsMiddleware())
// 5. Rate limiting (prevent abuse)
.use(rateLimitMiddleware())
// 6. Request validation (validate content)
.use(validationMiddleware());
}
Error handling middleware should be near the top of the middleware stack to catch errors from all downstream middleware and handlers.
Best Practices
1. Initialize Once
// Good: Initialize in root middleware
Handler middleware(Handler handler) {
if (!Modular.isInitialized) {
Modular.initialize(AppModule());
}
return handler.use(nestFrogMiddleware(AppModule()));
}
// Avoid: Multiple initializations
Handler middleware(Handler handler) {
Modular.initialize(AppModule()); // May cause issues
return handler.use(nestFrogMiddleware(AppModule()));
}
2. Order Middleware Logically
Handler middleware(Handler handler) {
return handler
.use(nestFrogMiddleware(AppModule())) // First: DI
.use(errorHandlingMiddleware()) // Second: Error handling
.use(loggingMiddleware()) // Third: Logging
.use(authMiddleware()); // Fourth: Auth
}
3. Use Services from Container
Middleware customMiddleware() {
return (handler) {
return (context) async {
// Access services through Modular
final service = Modular.get<MyService>();
// Use the service
await service.doSomething();
return handler(context);
};
};
}