# Cache
- [Introduction](#introduction)
- [Configuration](#configuration)
- [Retrieving Items](#retrieving-items)
- [Storing Items](#storing-items)
- [The Remember Method](#the-remember-method)
- [Removing Items](#removing-items)
- [Custom Cache Drivers](#custom-cache-drivers)
## Introduction
Magic provides an expressive, unified API for various caching backends. The framework ships with a native `FileStore` driver that supports both Mobile/Desktop (File System) and Web (LocalStorage).
Caching is essential for reducing API calls, storing computed values, and improving application performance.
## Configuration
### Enabling Cache Support
Add `CacheServiceProvider` to your providers in `config/app.dart`:
```dart
'providers': [
(app) => CacheServiceProvider(app),
// ... other providers
],
```
### Cache Configuration
Create `lib/config/cache.dart`:
```dart
import 'package:magic/magic.dart';
Map get cacheConfig => {
'cache': {
'driver': FileStore(fileName: 'magic_cache'),
'ttl': 3600, // Default TTL in seconds
},
};
```
## Retrieving Items
Use the `Cache` facade to retrieve items from the cache:
```dart
// Basic retrieval
final value = await Cache.get('key');
// With default value
final username = await Cache.get('username', defaultValue: 'Guest');
// Check existence
if (await Cache.has('user_settings')) {
final settings = await Cache.get('user_settings');
}
```
## Storing Items
Store items with optional TTL (time-to-live):
```dart
// With custom TTL
await Cache.put('key', 'value', ttl: Duration(minutes: 10));
// With default TTL from config
await Cache.put('key', 'value');
// Store any serializable data
await Cache.put('user', {
'id': 1,
'name': 'John',
'email': 'john@example.com',
});
```
## The Remember Method
The most powerful caching pattern—retrieve from cache or compute and store:
```dart
final users = await Cache.remember(
'users',
Duration(minutes: 5),
() async {
return await Http.get('/users');
},
);
```
This method:
1. Checks if `users` exists in cache
2. If yes, returns the cached value
3. If no, calls the closure, stores the result, and returns it
### API Response Caching
```dart
class UserController extends MagicController {
Future> getUsers() async {
return await Cache.remember('all_users', Duration(minutes: 10), () async {
final response = await Http.get('/users');
return (response.body as List).map((u) => User.fromMap(u)).toList();
});
}
}
```
### Computed Values
```dart
final dashboardStats = await Cache.remember('dashboard_stats', Duration(hours: 1), () async {
return {
'total_users': await User.count(),
'active_monitors': await Monitor.where('is_active', true).count(),
'incidents_today': await Incident.whereDate('created_at', Carbon.today()).count(),
};
});
```
## Removing Items
```dart
// Remove a single item
await Cache.forget('users');
// Clear entire cache
await Cache.flush();
```
### Invalidating Related Cache
```dart
class UserController extends MagicController {
Future updateUser(Map data) async {
final response = await Http.put('/users/${data['id']}', data: data);
if (response.successful) {
// Invalidate related caches
await Cache.forget('all_users');
await Cache.forget('user_${data['id']}');
await Cache.forget('dashboard_stats');
}
}
}
```
## Custom Cache Drivers
Implement `CacheStore` for custom backends:
```dart
class RedisStore implements CacheStore {
final RedisClient _client;
RedisStore(this._client);
@override
Future init() async {
await _client.connect();
}
@override
Future get(String key, {dynamic defaultValue}) async {
final value = await _client.get(key);
if (value == null) return defaultValue;
return jsonDecode(value);
}
@override
Future put(String key, dynamic value, {Duration? ttl}) async {
final encoded = jsonEncode(value);
if (ttl != null) {
await _client.setex(key, ttl.inSeconds, encoded);
} else {
await _client.set(key, encoded);
}
}
@override
Future has(String key) async {
return await _client.exists(key) > 0;
}
@override
Future forget(String key) async {
await _client.del(key);
}
@override
Future flush() async {
await _client.flushdb();
}
}
```
Use your custom driver in config:
```dart
'cache': {
'driver': RedisStore(RedisClient()),
},
```
> [!TIP]
> Use caching for expensive API calls, complex computations, and data that doesn't change frequently.