auto_go_route 1.0.0 copy "auto_go_route: ^1.0.0" to clipboard
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);
}
// 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: #

  1. Replace route definitions with @AutoGoRoute annotations
  2. Create a route base class extending _$YourRouteClass
  3. Run code generation: dart run build_runner build
  4. Update navigation calls to use generated route instances
  5. Register routes in RouteRegistry for additional features

Contributing #

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. 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 #

Made with ❤️ by Arvind Sangwan

8
likes
0
points
225
downloads

Publisher

verified publishermohesu.com

Weekly Downloads

A powerful, type-safe, and feature-rich routing package for Flutter GoRouter with automatic code generation.

Repository (GitHub)
View/report issues

Topics

#routing #navigation #auto-route #go-router #type-safety

Documentation

Documentation

Funding

Consider supporting this project:

github.com

License

unknown (license)

Dependencies

equatable, flutter, go_router, meta

More

Packages that depend on auto_go_route