I’m working on adding offline support to my app. My requirement is to queue and temporarily store an API request (including headers, request body, and endpoint) when the user loses internet connection, so that it can be automatically executed once the connection is restored.
Is there a way to store the entire API request in a queue and trigger it later when the user regains connectivity?
For context, I’m using Dio and Retrofit for API calls.
2
For offline support, I’m using the following logic. I hope it helps.
Each model has a boolean field called isSynced
when saving data to local storage. When creating a new model, isSynced
should be set to false
. Once the data is synced, change it to true
. This process should be repeated when updating: set isSynced
to false
after making changes, and set it to true
once the updates are synced with the server. By doing this, I don’t need to make API calls when saving data. Instead, I write it to the local database and periodically sync it with the server. This, in my understanding, is what “offline-first” means.
This is the logic for how it works. But what about syncing data to the server? Here’s the approach I use in my production applications, with some dummy data.
First, create a local database model that follows the specifications I mentioned. Here’s an example model for our case:
class ExampleModel {
ExampleModel({
required this.title,
required this.createdAt,
required this.id,
this.isActive=true,
this.isSynced=false,
this.deletedAt,
this.updatedAt,
});
String id;
String title;
DateTime createdAt;
DateTime? deletedAt;
bool isSynced;
DateTime? updatedAt;
bool isActive;
}
You’ll also need to create a manager that periodically checks the models in the local database and syncs the ones that haven’t been synced yet.
Here is a simple manager that does it for you. Managing this kind of operations from single class is a good approach since you might need to add additional control in the future such as making it only for premium users etc.
class SyncManager {
Timer? _syncTimer;
Future<void> syncUnsyncedDocuments() async {
///Here is a mock variable. In your case you can use related query unsynced document logic based on which local db you use.
final unsyncedDocuments = [
ExampleModel(title: 'Example 1',isSynced: false,createdAt: DateTime.now(),id: '1'),
ExampleModel(title: 'Example 2',isSynced: false,createdAt: DateTime.now(),id: '2'),
ExampleModel(title: 'Example 3',isSynced: false,createdAt: DateTime.now(),id: '3'),
];
for (final doc in unsyncedDocuments) {
final success = await _syncDocumentToServer(doc);
if (success) {
// Set isSynced flag to true and update it in the local db.
}
}
}
Future<bool> _syncDocumentToServer(ExampleModel doc) async {
try {
// Make your API call here to sync your function to the server. Return true if call is successful and false if not.
return true;
} catch (e) {
return false;
}
}
void startSyncing({Duration interval = const Duration(minutes: 5)}) {
_syncTimer = Timer.periodic(interval, (timer) {
syncUnsyncedDocuments();
});
}
void stopSyncing() {
_syncTimer?.cancel();
}
}
You just need to call startSyncing
function to basically start syncing 🙂
I hope it helps.