JSON Assets Demo

Loading policies from external JSON asset files

JSON Assets Demo

This example demonstrates how to load and manage policies from external JSON asset files using the initializeFromJsonAssets method. This approach is ideal for applications that need to bundle policy configurations with the app or load them from external sources.

šŸŽÆ Demo Overview

The JSON Assets Demo showcases:

  • External Policy Loading: Loading policies from JSON files bundled as assets
  • Dynamic Role Management: Interactive role selection and permission testing
  • Real-time Validation: Testing permissions against loaded policies
  • Error Handling: Graceful handling of initialization failures
  • Visual Feedback: Clear status indicators and result displays

šŸ“ Asset File Structure

The demo uses a JSON asset file located at assets/policies/user_roles.json with the following structure:

{
  "admin": {
    "allowedContent": [
      "read",
      "write",
      "delete",
      "manage_users",
      "system_config",
      "all",
      "admin_panel",
      "user_management",
      "system_settings"
    ]
  },
  "manager": {
    "allowedContent": [
      "read",
      "write",
      "manage_team",
      "team_content",
      "reports",
      "analytics",
      "public"
    ]
  },
  "editor": {
    "allowedContent": [
      "read",
      "write",
      "publish",
      "content_creation",
      "drafts",
      "published_content",
      "public"
    ]
  },
  "viewer": {
    "allowedContent": ["read", "public", "published_content", "reports"]
  },
  "guest": {
    "allowedContent": ["read", "public"]
  }
}

šŸš€ Complete Demo Implementation

import 'package:flutter/material.dart';
import 'package:flutter_policy_engine/flutter_policy_engine.dart';

class JsonAssetsDemo extends StatefulWidget {
  const JsonAssetsDemo({super.key});

  @override
  State<JsonAssetsDemo> createState() => _JsonAssetsDemoState();
}

class _JsonAssetsDemoState extends State<JsonAssetsDemo> {
  final PolicyManager _policyManager = PolicyManager();
  bool _isInitialized = false;
  bool _isLoading = false;
  String _selectedRole = 'admin';
  String _selectedPermission = 'read';
  String _lastResult = '';
  String _errorMessage = '';

  final List<String> _availableRoles = [
    'admin',
    'manager',
    'editor',
    'viewer',
    'guest',
  ];

  final List<String> _availablePermissions = [
    'read',
    'write',
    'delete',
    'manage_users',
    'system_config',
    'manage_team',
    'publish',
  ];

  @override
  void initState() {
    super.initState();
    _initializePolicyManager();
  }

  Future<void> _initializePolicyManager() async {
    setState(() {
      _isLoading = true;
      _errorMessage = '';
    });

    try {
      await _policyManager
          .initializeFromJsonAssets('assets/policies/user_roles.json');

      setState(() {
        _isInitialized = _policyManager.isInitialized;
        _isLoading = false;
        _lastResult = _isInitialized
            ? 'āœ… Policy manager initialized successfully from JSON assets!'
            : 'āŒ Failed to initialize policy manager';
      });
    } catch (e) {
      setState(() {
        _isLoading = false;
        _errorMessage = 'Error: $e';
        _lastResult = 'āŒ Initialization failed';
      });
    }
  }

  void _testPermission() {
    if (!_isInitialized) {
      setState(() {
        _lastResult = 'āŒ Policy manager not initialized';
      });
      return;
    }

    try {
      final role = _policyManager.roles[_selectedRole];
      if (role != null) {
        final hasPermission = role.allowedContent.contains(_selectedPermission);
        setState(() {
          _lastResult = hasPermission
              ? 'āœ… Role "$_selectedRole" has permission "$_selectedPermission"'
              : 'āŒ Role "$_selectedRole" does NOT have permission "$_selectedPermission"';
        });
      } else {
        setState(() {
          _lastResult = 'āŒ Role "$_selectedRole" not found';
        });
      }
    } catch (e) {
      setState(() {
        _lastResult = 'āŒ Error testing permission: $e';
      });
    }
  }

  void _getRoleInfo() {
    if (!_isInitialized) {
      setState(() {
        _lastResult = 'āŒ Policy manager not initialized';
      });
      return;
    }

    try {
      final role = _policyManager.roles[_selectedRole];
      if (role != null) {
        setState(() {
          _lastResult = '''
āœ… Role Information for "$_selectedRole":
   Name: ${role.name}
   Allowed Content: ${role.allowedContent.join(', ')}
''';
        });
      } else {
        setState(() {
          _lastResult = 'āŒ Role "$_selectedRole" not found';
        });
      }
    } catch (e) {
      setState(() {
        _lastResult = 'āŒ Error getting role info: $e';
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('JSON Assets Demo'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // Initialization Status Card
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Row(
                      children: [
                        Icon(
                          _isInitialized ? Icons.check_circle : Icons.error,
                          color: _isInitialized ? Colors.green : Colors.red,
                        ),
                        const SizedBox(width: 8),
                        Text(
                          'Policy Manager Status',
                          style: Theme.of(context).textTheme.titleMedium,
                        ),
                      ],
                    ),
                    const SizedBox(height: 8),
                    if (_isLoading)
                      const LinearProgressIndicator()
                    else
                      Text(
                        _isInitialized
                            ? 'āœ… Initialized from JSON assets'
                            : 'āŒ Not initialized',
                        style: Theme.of(context).textTheme.bodyMedium,
                      ),
                    if (_errorMessage.isNotEmpty) ...[
                      const SizedBox(height: 8),
                      Text(
                        _errorMessage,
                        style: Theme.of(context).textTheme.bodySmall?.copyWith(
                              color: Colors.red,
                            ),
                      ),
                    ],
                    const SizedBox(height: 16),
                    ElevatedButton.icon(
                      onPressed: _isLoading ? null : _initializePolicyManager,
                      icon: const Icon(Icons.refresh),
                      label: const Text('Reinitialize'),
                    ),
                  ],
                ),
              ),
            ),
            const SizedBox(height: 16),

            // Role Selection Card
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Role Selection',
                      style: Theme.of(context).textTheme.titleMedium,
                    ),
                    const SizedBox(height: 16),
                    DropdownButtonFormField<String>(
                      value: _selectedRole,
                      decoration: const InputDecoration(
                        labelText: 'Select Role',
                        border: OutlineInputBorder(),
                      ),
                      items: _availableRoles.map((role) {
                        return DropdownMenuItem(
                          value: role,
                          child: Text(role),
                        );
                      }).toList(),
                      onChanged: (value) {
                        if (value != null) {
                          setState(() {
                            _selectedRole = value;
                          });
                        }
                      },
                    ),
                  ],
                ),
              ),
            ),
            const SizedBox(height: 16),

            // Permission Testing Card
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Permission Testing',
                      style: Theme.of(context).textTheme.titleMedium,
                    ),
                    const SizedBox(height: 16),
                    DropdownButtonFormField<String>(
                      value: _selectedPermission,
                      decoration: const InputDecoration(
                        labelText: 'Select Permission',
                        border: OutlineInputBorder(),
                      ),
                      items: _availablePermissions.map((permission) {
                        return DropdownMenuItem(
                          value: permission,
                          child: Text(permission),
                        );
                      }).toList(),
                      onChanged: (value) {
                        if (value != null) {
                          setState(() {
                            _selectedPermission = value;
                          });
                        }
                      },
                    ),
                    const SizedBox(height: 16),
                    ElevatedButton.icon(
                      onPressed: _isInitialized ? _testPermission : null,
                      icon: const Icon(Icons.security),
                      label: const Text('Test Permission'),
                      style: ElevatedButton.styleFrom(
                        backgroundColor: Colors.blue,
                        foregroundColor: Colors.white,
                      ),
                    ),
                  ],
                ),
              ),
            ),
            const SizedBox(height: 16),

            // Role Information Card
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Role Information',
                      style: Theme.of(context).textTheme.titleMedium,
                    ),
                    const SizedBox(height: 16),
                    ElevatedButton.icon(
                      onPressed: _isInitialized ? _getRoleInfo : null,
                      icon: const Icon(Icons.info),
                      label: const Text('Get Role Details'),
                      style: ElevatedButton.styleFrom(
                        backgroundColor: Colors.orange,
                        foregroundColor: Colors.white,
                      ),
                    ),
                  ],
                ),
              ),
            ),
            const SizedBox(height: 16),

            // Results Card
            if (_lastResult.isNotEmpty)
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        'Test Results',
                        style: Theme.of(context).textTheme.titleMedium,
                      ),
                      const SizedBox(height: 16),
                      Container(
                        width: double.infinity,
                        padding: const EdgeInsets.all(12),
                        decoration: BoxDecoration(
                          color: Colors.grey[100],
                          borderRadius: BorderRadius.circular(8),
                          border: Border.all(color: Colors.grey[300]!),
                        ),
                        child: Text(
                          _lastResult,
                          style:
                              Theme.of(context).textTheme.bodyMedium?.copyWith(
                                    fontFamily: 'monospace',
                                  ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
          ],
        ),
      ),
    );
  }
}

šŸ”§ Setup Requirements

1. Asset Declaration

Add the JSON asset file to your pubspec.yaml:

flutter:
  assets:
    - assets/policies/user_roles.json

2. File Structure

Ensure your project has the following structure:

your_app/
ā”œā”€ā”€ assets/
│   └── policies/
│       └── user_roles.json
ā”œā”€ā”€ lib/
│   └── json_assets_demo.dart
└── pubspec.yaml

šŸŽØ Key Features Explained

Initialization Process

The demo initializes the policy manager using initializeFromJsonAssets:

await _policyManager.initializeFromJsonAssets('assets/policies/user_roles.json');

This method:

  • Loads the JSON file from assets
  • Parses the JSON structure
  • Creates Role objects from the parsed data
  • Initializes the policy manager with the loaded policies

Error Handling

The implementation includes comprehensive error handling:

try {
  await _policyManager.initializeFromJsonAssets('assets/policies/user_roles.json');
  setState(() {
    _isInitialized = _policyManager.isInitialized;
    _isLoading = false;
    _lastResult = _isInitialized
        ? 'āœ… Policy manager initialized successfully from JSON assets!'
        : 'āŒ Failed to initialize policy manager';
  });
} catch (e) {
  setState(() {
    _isLoading = false;
    _errorMessage = 'Error: $e';
    _lastResult = 'āŒ Initialization failed';
  });
}

Permission Testing

The demo provides real-time permission testing:

void _testPermission() {
  if (!_isInitialized) return;

  final role = _policyManager.roles[_selectedRole];
  if (role != null) {
    final hasPermission = role.allowedContent.contains(_selectedPermission);
    // Update UI with result
  }
}

šŸŽÆ Use Cases

This approach is ideal for:

  • Configuration Management: Centralizing policy configurations in external files
  • Dynamic Updates: Updating policies without code changes
  • Environment-Specific Policies: Different policies for development, staging, and production
  • Localization: Different policies for different regions or user groups
  • A/B Testing: Testing different policy configurations

šŸ” Best Practices

1. Asset Validation

Always validate your JSON structure before deployment:

// Validate JSON structure
try {
  final testManager = PolicyManager();
  await testManager.initializeFromJsonAssets('assets/policies/user_roles.json');
  print('āœ… JSON structure is valid');
} catch (e) {
  print('āŒ JSON structure error: $e');
}

2. Error Recovery

Implement fallback mechanisms:

Future<void> initializeWithFallback() async {
  try {
    await _policyManager.initializeFromJsonAssets('assets/policies/user_roles.json');
  } catch (e) {
    // Fallback to default policies
    await _policyManager.initialize(defaultPolicies);
  }
}

šŸš€ Next Steps