auto_go_route 1.0.0
auto_go_route: ^1.0.0 copied to clipboard
A powerful, type-safe, and feature-rich routing package for Flutter GoRouter with automatic code generation.
Auto Go Route #
A powerful, type-safe, and feature-rich routing package for Flutter with automatic code generation. Built on top of GoRouter with enhanced developer experience and production-ready features.
[auto_go_route.webp]Features #
✨ Type-Safe Navigation - Compile-time route validation and parameter checking
🔄 Automatic Code Generation - Zero boilerplate with @AutoGoRoute
annotations
📱 Flutter-First - Built specifically for Flutter with full widget integration
🎯 Parameter Auto-Detection - Automatically extract required/optional parameters from paths
📚 Documentation Generation - Auto-generate route documentation in multiple formats
🔍 Route Registry - Centralized route management with validation and analytics
⚡ Performance Monitoring - Built-in performance tracking and optimization
🛡️ Production Ready - Comprehensive error handling and validation
🐚 Shell Routes - Support for nested navigation with shell routes
🔗 Nested Routes - Hierarchical route structure with parent-child relationships
Installation #
Add the following to your pubspec.yaml
:
dependencies:
auto_go_route: ^1.0.0
go_router: ^16.0.0
dev_dependencies:
build_runner: ^2.4.15
auto_go_route_generator: ^1.0.0
Then run:
flutter pub get
Quick Start #
1. Annotate Your Pages #
import 'package:flutter/material.dart';
import 'package:auto_go_route/auto_go_route.dart';
@AutoGoRoute(
path: '/login',
name: 'login',
description: 'User login page',
)
class LoginPage extends StatelessWidget {
const LoginPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Login')),
body: const Center(child: Text('Login Page')),
);
}
}
2. Create Route Base Class #
import 'package:auto_go_route/auto_go_route.dart';
import 'package:go_router/go_router.dart';
@AutoGoRouteBase()
class AppRoutes extends _$AppRoutes {
@override
GoRouter build() {
return GoRouter(
initialLocation: '/login',
routes: _buildNestedRoutes(),
errorBuilder: (context, state) {
return Scaffold(
body: Center(
child: Text('Error: ${state.error}'),
),
);
},
);
}
}
3. Generate Routes #
dart run build_runner build
4. Navigate with Type Safety #
// Access generated routes
final routes = AppRoutes();
// Simple navigation
context.go(routes.loginRoute.path);
// Navigation with parameters
context.goToRoute(routes.userProfileRoute, params: {
'userId': 'user123',
'tab': 'settings',
});
// Using path with parameters
final userPath = routes.userProfileRoute.pathWith(
userId: 'user123',
tab: 'settings',
);
context.go(userPath);
Advanced Usage #
Routes with Parameters #
@AutoGoRoute(
path: '/user/:userId/profile/:tab?',
name: 'userProfile',
description: 'User profile with optional tab',
)
class UserProfilePage extends StatelessWidget {
final String userId;
final String? tab;
const UserProfilePage({
super.key,
required this.userId,
this.tab,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Profile: $userId')),
body: Column(
children: [
Text('User ID: $userId'),
if (tab != null) Text('Tab: $tab'),
],
),
);
}
}
Shell Routes for Navigation Structure #
@AutoGoRouteShell(
path: '/dashboard',
name: 'dashboardShell',
description: 'Main dashboard shell',
isStateful: false, // default is false
)
class DashboardShell extends StatelessWidget {
final Widget child;
const DashboardShell({super.key, required this.child});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Dashboard')),
body: child,
bottomNavigationBar: BottomNavigationBar(
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
],
),
);
}
}
Nested Routes #
@AutoGoRoute(
path: 'home', // Relative path for nested route
parent: DashboardShell,
name: 'dashboardHome',
)
class DashboardHomePage extends StatelessWidget {
const DashboardHomePage({super.key});
@override
Widget build(BuildContext context) {
return const Center(
child: Text('Dashboard Home'),
);
}
}
Stateful Shell Routes #
@AutoGoRouteShell(
path: '/main',
name: 'mainShell',
isStateful: true, // Enables StatefulShellRoute
)
class MainShell extends StatelessWidget {
final Widget child;
const MainShell({super.key, required this.child});
@override
Widget build(BuildContext context) {
return Scaffold(
body: child,
bottomNavigationBar: const BottomNavigationBar(
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(icon: Icon(Icons.settings), label: 'Settings'),
],
),
);
}
}
Type-Safe Parameter Extraction #
// In your route builder - parameters are automatically extracted
@AutoGoRoute(path: '/product/:id/:variant?')
class ProductPage extends StatelessWidget {
final String id;
final String? variant;
const ProductPage({
super.key,
required this.id,
this.variant,
});
@override
Widget build(BuildContext context) {
// Parameters are automatically extracted and type-converted
return Scaffold(
body: Column(
children: [
Text('Product ID: $id'),
if (variant != null) Text('Variant: $variant'),
],
),
);
}
}
// Manual parameter extraction (if needed)
extension ProductRouteExtension on GoRouterState {
String get productId => getParam('id');
String? get productVariant => getOptionalParam('variant', null);
}
Navigation Extensions #
// Type-safe navigation with auto-completion
context.goToRoute(AppRoutes().productRoute, params: {
'id': 'product123',
'variant': 'red',
});
// Navigation with queries
context.goToRoute(AppRoutes().searchRoute,
params: {'query': 'flutter'},
queries: {'category': 'development', 'sort': 'newest'}
);
// Conditional navigation
context.goToRouteIfAuth(
AppRoutes().dashboardRoute,
isAuthenticated: true,
fallbackRoute: AppRoutes().loginRoute,
);
// Safe navigation
context.safePop(); // Won't crash if can't pop
// Navigation with parameters validation
context.goWithParams(AppRoutes().userRoute, {
'userId': 123, // Automatically converted to string
'tab': 'settings',
});
Generated Code Example #
For a route definition like:
@AutoGoRoute(
path: '/user/:userId/settings/:tab?',
name: 'userSettings',
)
class UserSettingsPage extends StatelessWidget {
final String userId;
final String? tab;
// ...
}
The generator creates:
class UserSettingsPageRoute extends RoutePaths {
UserSettingsPageRoute() : super(
path: '/user/:userId/settings/:tab?',
name: 'userSettings',
builder: (context, state) => UserSettingsPage(
userId: state.getParam('userId'),
tab: state.getParam('tab'),
),
);
String pathWith({
required String userId,
String? tab,
Map? queries,
}) {
final params = {
'userId': userId,
if (tab != null) 'tab': tab,
};
return pathWithParams(params, queries: queries);
}
String navigateToUserSettingsPage({
required String userId,
String? tab,
Map? queries,
}) {
return pathWith(userId: userId, tab: tab, queries: queries);
}
}
Route Registry and Documentation #
void main() {
// Access all generated routes
final appRoutes = AppRoutes();
// Register all routes
RouteRegistry().registerAll(appRoutes.allRoutes);
// Validate routes at startup
RouteRegistry().validateAllRoutes();
// Generate documentation
final docs = RouteRegistry().generateDocumentation(
format: DocumentationFormat.markdown,
includeMetadata: true,
includeParameters: true,
);
runApp(MyApp());
}
Authentication and Middleware #
@AutoGoRoute(
path: '/admin/dashboard',
requireAuth: true,
middleware: ['authMiddleware', 'adminMiddleware'],
)
class AdminDashboard extends StatelessWidget {
// Your admin dashboard implementation
}
API Reference #
Annotations #
@AutoGoRoute
@AutoGoRoute({
required String path, // Route path with parameters
String? name, // Optional route name
String? description, // Description for documentation
String? redirect, // Redirect function name
bool requireAuth = false, // Authentication requirement
Type? parent, // Parent route class for nesting
List children = const [], // Child routes
List middleware = const [], // Middleware functions
})
@AutoGoRouteShell
@AutoGoRouteShell({
required String path, // Shell route path
String? name, // Optional shell name
String? description, // Description for documentation
String? navigatorKey, // Navigator key identifier
Type? parent, // Parent shell for nesting
bool isStateful = false, // Use StatefulShellRoute
})
@AutoGoRouteBase
@AutoGoRouteBase({
String? initialLocation, // Initial route location
String? errorBuilder, // Error page builder function name
String? redirect, // Global redirect function name
})
Extensions #
GoRouterStateTypeExtension
T getParam(String key) // Get typed parameter
T getRequiredParam(String key) // Get required parameter
T getOptionalParam(String key, T defaultValue) // Get optional parameter
Map getTypedPathParameters() // Get all path parameters
Map getTypedQueryParameters() // Get all query parameters
bool hasParam(String key) // Check if parameter exists
TypeSafeNavigation
void goToRoute(RoutePaths route, {...}) // Navigate to route
void pushRoute(RoutePaths route, {...}) // Push route
void replaceRoute(RoutePaths route, {...}) // Replace current route
void goWithParams(T route, Map params) // Navigate with typed params
void goToRouteIfAuth(RoutePaths route, bool isAuth, {...}) // Conditional navigation
void safePop([Object? result]) // Safe pop operation
Route Registry #
RouteRegistry
void register(RoutePaths route) // Register single route
void registerAll(List routes) // Register multiple routes
void validateAllRoutes() // Validate all routes
String generateDocumentation({...}) // Generate documentation
RegistryStatistics get statistics // Get registry statistics
Best Practices #
1. Route Organization #
// Use the generated route base class
class AppRoutes extends _$AppRoutes {
// Access individual routes
static HomePageRoute get home => AppRoutes().homePageRoute;
static ProfilePageRoute get profile => AppRoutes().profilePageRoute;
}
2. Parameter Validation #
@AutoGoRoute(path: '/user/:userId')
class UserPage extends StatelessWidget {
final String userId;
const UserPage({required this.userId});
@override
Widget build(BuildContext context) {
// Validate userId format
if (!RegExp(r'^[a-zA-Z0-9]+$').hasMatch(userId)) {
return const ErrorPage(message: 'Invalid user ID format');
}
return Scaffold(/* ... */);
}
}
3. Shell Route Structure #
// Main app shell
@AutoGoRouteShell(path: '/app', isStateful: true)
class AppShell extends StatelessWidget { /* ... */ }
// Feature-specific shell
@AutoGoRouteShell(path: '/admin', parent: AppShell)
class AdminShell extends StatelessWidget { /* ... */ }
// Pages within shells
@AutoGoRoute(path: 'dashboard', parent: AdminShell)
class AdminDashboard extends StatelessWidget { /* ... */ }
4. Testing Routes #
void main() {
group('Route Tests', () {
test('should generate correct path with parameters', () {
final route = UserProfilePageRoute();
final path = route.pathWith(userId: 'user123', tab: 'settings');
expect(path, equals('/user/user123/profile/settings'));
});
test('should validate required parameters', () {
final route = UserProfilePageRoute();
expect(
() => route.pathWith(userId: ''), // Empty required param
throwsA(isA()),
);
});
});
}
Package Structure #
auto_go_route/
├── lib/
│ ├── auto_go_route.dart // Main export file
│ └── src/
│ ├── annotations/
│ │ └── auto_go_route.dart // Route annotations
│ ├── base/
│ │ ├── route_paths.dart // Base route class
│ │ ├── nested_route_paths.dart // Nested route base
│ │ └── shell_route_paths.dart // Shell route base
│ ├── extensions/
│ │ ├── go_router_state_extension.dart // Parameter extraction
│ │ ├── navigation_extensions.dart // Navigation helpers
│ │ └── string.dart // String utilities
│ ├── registry/
│ │ └── route_registry.dart // Route management
│ ├── utils/
│ │ └── route_utils.dart // Route utilities
│ └── exceptions/
│ └── route_exceptions.dart // Custom exceptions
└── generator/
├── lib/
│ ├── auto_go_route_generator.dart // Main generator export
│ ├── builder.dart // Build configuration
│ └── src/
│ ├── generators/
│ │ └── route_generator.dart // Code generator
│ └── utils/
│ └── generator_utils.dart // Generator utilities
├── build.yaml // Build configuration
└── pubspec.yaml // Generator dependencies
Migration Guide #
From manual GoRouter setup: #
Before:
GoRoute(
path: '/user/:id',
builder: (context, state) {
final id = state.pathParameters['id'] ?? '';
return UserPage(userId: id);
},
)
class UserPage extends StatelessWidget {
final String id;
const UserPage({required this.id});
// ...
}
After:
@AutoGoRoute(path: '/user/:id')
class UserPage extends StatelessWidget {
final String id;
const UserPage({required this.id});
// ...
}
From other routing packages: #
- Replace route definitions with
@AutoGoRoute
annotations - Create a route base class extending
_$YourRouteClass
- Run code generation:
dart run build_runner build
- Update navigation calls to use generated route instances
- Register routes in
RouteRegistry
for additional features
Contributing #
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
Development Setup #
# Clone the repository
git clone https://github.com/itsarvinddev/auto_go_route.git
# Install dependencies
cd auto_go_route
flutter pub get
# Install generator dependencies
cd generator
dart pub get
cd ..
# Generate code
dart run build_runner build
# Run tests
flutter test
# Run example app
cd example
flutter run
License #
This project is licensed under the MIT License - see the LICENSE file for details.
Support #
- Github: itsarvinddev
- X: @itsarvinddev
- Issues: GitHub Issues
Made with ❤️ by Arvind Sangwan