dynamic_schema_mapper 0.1.0
dynamic_schema_mapper: ^0.1.0 copied to clipboard
Automatically map dynamic backend JSON to type-safe Dart structures at runtime without model classes. Perfect for evolving APIs.
#
Runtime JSON Model Generator for Flutter β Automatically adapt to evolving backend JSON structures without manual model updates.
π― #
Backend APIs evolve constantlyβnew fields get added, old ones removed, types change. Traditional model classes break easily, requiring constant maintenance. Dynamic Backend Schema Mapper solves this by:
- β Zero Model Classes β No manual model updates needed
- β
Type-Safe Access β
getString(),getInt(),getBool()with defaults - β Auto-Adaptation β Handles backend changes automatically
- β Schema Detection β Get notified when backend structure changes
- β Deep Nesting β Fully supports nested objects and lists
- β Crash Prevention β Default values prevent null reference errors
π± #
#

Demonstrating real-time JSON parsing with type-safe getters and default values
#

Automatic detection and notification of backend schema changes
π¦ #
Add to your pubspec.yaml:
dependencies:
dynamic_schema_mapper: ^0.1.0
Then run:
flutter pub get
π #
#
import 'package:dynamic_schema_mapper/dynamic_schema_mapper.dart';
// Parse any JSON response
final jsonResponse = {
'id': 123,
'name': 'John Doe',
'age': 30,
'premium': true,
'balance': 1250.50,
};
final schema = DynamicSchema.parse(jsonResponse);
// Type-safe access with automatic defaults
final name = schema.getString('name'); // "John Doe"
final age = schema.getInt('age'); // 30
final premium = schema.getBool('premium'); // true
final balance = schema.getDouble('balance'); // 1250.50
// Non-existent keys return safe defaults
final phone = schema.getString('phone', defaultValue: 'N/A'); // "N/A"
#
final response = {
'user': {
'name': 'Alice',
'address': {
'city': 'Springfield',
'zipcode': 12345,
}
}
};
final schema = DynamicSchema.parse(response);
// Navigate nested structures
final user = schema.getNested('user');
final address = user?.getNested('address');
print(address?.getString('city')); // "Springfield"
print(address?.getInt('zipcode')); // 12345
// Or use dot notation
print(schema.getValueAtPath('user.address.city')); // "Springfield"
#
final response = {
'products': [
{'id': 1, 'name': 'Laptop', 'price': 999.99},
{'id': 2, 'name': 'Mouse', 'price': 29.99},
]
};
final schema = DynamicSchema.parse(response);
final products = schema.getList('products');
for (final product in products) {
print('${product.getString('name')}: \$${product.getDouble('price')}');
}
// Output:
// Laptop: $999.99
// Mouse: $29.99
#
Get notified automatically when your backend structure changes:
// Enable change detection
DynamicSchema.enableSchemaDetection((changes) {
print('β οΈ Backend schema changed!');
for (final change in changes) {
print('β’ $change');
}
});
// First API call
DynamicSchema.parse({'id': 1, 'name': 'Product A', 'price': 99.99});
// Backend evolves - new fields added
DynamicSchema.parse({
'id': 2,
'name': 'Product B',
'price': 149.99,
'category': 'Electronics', // NEW!
'inStock': true, // NEW!
});
// Console output:
// β οΈ Backend schema changed!
// β’ Fields Added: category
// β’ Fields Added: inStock
π¨ #
#
All getters include default values to prevent crashes:
schema.getString('key', defaultValue: 'default');
schema.getInt('key', defaultValue: 0);
schema.getDouble('key', defaultValue: 0.0);
schema.getBool('key', defaultValue: false);
#
// Get all keys
final keys = schema.keys; // ['id', 'name', 'age']
// Check if key exists
if (schema.hasKey('email')) {
print(schema.getString('email'));
}
// Get all paths (including nested)
final paths = schema.getAllPaths();
// ['user', 'user.name', 'user.address', 'user.address.city']
// Get schema structure (types only)
final structure = schema.getSchemaStructure();
#
// Pretty print
print(schema.toJsonString(pretty: true));
// Compact
final json = schema.toJsonString();
#
Cache schemas locally for offline use or comparison:
import 'package:dynamic_schema_mapper/cache_manager.dart';
final cache = SchemaCacheManager(
namespace: 'my_app',
cacheDuration: Duration(hours: 24),
);
// Save schema
await cache.saveSchema('users', schema.getSchemaStructure());
// Load cached schema
final cachedSchema = await cache.loadSchema('users');
// Check if valid cache exists
if (await cache.hasValidCache('users')) {
print('Using cached schema');
}
πΌοΈ #
| [Basic Usage] | [Basic Usage] | [Nested Objects] | [Lists And Arrays] | [Dashboard] |
| Home Screen | Basic JSON Parsing | Nested Objects | Lists And Arrays | Dashboard |
ποΈ #
dynamic_schema_mapper/
ββ lib/
β ββ dynamic_schema_mapper.dart # Main API
β ββ src/
β ββ schema_node.dart # Core data structure
β ββ schema_parser.dart # JSON β SchemaNode
β ββ schema_diff.dart # Change detection
β ββ cache_manager.dart # Optional caching
#
- SchemaNode: Represents JSON values (primitives, objects, lists)
- SchemaParser: Converts JSON to SchemaNode tree
- SchemaDiff: Detects changes between schemas
- CacheManager: Optional local schema storage
π #
// Complex e-commerce order
final order = DynamicSchema.parse(orderApiResponse);
// Customer info
final customer = order.getNested('customer');
print('Customer: ${customer?.getString('name')}');
print('Loyalty: ${customer?.getString('loyaltyTier')}');
// Order items
final items = order.getList('items');
for (final item in items) {
final name = item.getString('name');
final qty = item.getInt('quantity');
final price = item.getDouble('unitPrice');
print('$name: $qty Γ \$$price');
}
// Shipping address
final address = order.getNested('shipping')?.getNested('address');
print('Ship to: ${address?.getString('city')}, ${address?.getString('state')}');
// Payment
final payment = order.getNested('payment');
final paid = payment?.getBool('paid') ?? false;
print('Payment status: ${paid ? 'PAID' : 'PENDING'}');
π₯ #
#
final oldSchema = DynamicSchema.parse(oldApiResponse);
final newSchema = DynamicSchema.parse(newApiResponse);
final changes = DynamicSchema.compareSchemas(oldSchema, newSchema);
for (final change in changes) {
print(change);
}
#
// Print entire schema structure
schema.printTree();
// Output:
// object {
// name:
// string: John Doe
// age:
// integer: 30
// address:
// object {
// city:
// string: Springfield
// }
// }
β‘ #
- Fast Parsing: Minimal overhead compared to manual models
- Lazy Evaluation: Only processes accessed fields
- Memory Efficient: Shared references, no duplication
π : #
Performance varies based on JSON size and structure. The package is optimized for real-world use cases where flexibility is more important than raw speed.
The package is optimized for real-world scenarios where API flexibility and zero maintenance are priorities. Performance characteristics scale well with JSON size, with lazy evaluation ensuring only accessed fields are processed.
β οΈ #
- No Static Types: Fields are accessed dynamically at runtime
- No Code Generation: Everything happens at runtime
π€ #
Contributions are welcome! If you find a bug or have a feature request, please open an issue on GitHub.
π #
MIT License - see LICENSE file.
π¬ #
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Email: gargesamarth@gmail.com
β #
If this package helps your project, give it a β on GitHub!
Made with β€οΈ for the Flutter community