Flutter Data is an offline-first persistence framework that gives you a configurable REST client and powerful model relationships.
Heavily inspired by Ember Data and ActiveRecord
- Repositories for all models 🚀
- CRUD and custom remote endpoints
- StateNotifier watcher APIs
- Built for offline-first 🔌
- Hive-based local storage at its core
- Failure handling & retry API
- Intuitive APIs, effortless setup 💙
- Truly configurable and composable via Dart mixins and codegen
- Built-in Riverpod providers for all models
- Exceptional relationship support ⚡️
- Automatically synchronized, fully traversable relationship graph
- Reactive relationships
Check out the Documentation or the Tutorial 📚 where we build a TO-DO app from the ground up in record time.
See the quickstart guide for setup and boot configuration.
Prefer an example? Here's the Flutter Data sample setup app with support for Riverpod, Provider and get_it.
For a given User model annotated with @DataRepository:
@JsonSerializable()
@DataRepository([MyJSONServerAdapter])
classUserwithDataModel<User> {
@overridefinalint id; // ID can be of any typefinalString name;
User({this.id, this.name});
// `User.fromJson` and `toJson` optional
}
mixinMyJSONServerAdapteronRemoteAdapter<User> {
@overrideStringget baseUrl =>"https://my-json-server.typicode.com/flutterdata/demo/";
}After a code-gen build, Flutter Data will generate a Repository<User>
and utilities such as watchUser:
@overrideWidgetbuild(BuildContext context) {
final state =useProvider(watchUser(1).state);
if (state.isLoading) {
returnCenter(child:constCircularProgressIndicator());
}
final user = state.model;
returnText(user.name);
}watchUser(1) is a shortcut to repository.watchOne(1).
Let's see how to update the user:
GestureDetector(
onTap: () =>
context.read(usersRepositoryProvider).save(User(id:1, name:'Updated')),
child:Text('Update')
),repository.watchOne(1) will make an HTTP request (to https://my-json-server.typicode.com/flutterdata/demo/users/1 in this case), parse the incoming JSON and listen for any further changes to the User – whether those are local or remote!
state is of type DataState which has loading, error and data substates. Moreover, the watchOne notifier has a reload() function available, useful for the classic "pull-to-refresh" scenario.
In addition to the reactivity, DataModels get extensions and automatic relationships, ActiveRecord-style, so the above becomes:
GestureDetector(
onTap: () =>User(id:1, name:'Updated').init(context.read).save(),
child:Text('Update')
),Some other examples:
final todo =awaitTodo(title:'Finish docs').init(context.read).save();
// POST https://my-json-server.typicode.com/flutterdata/demo/todos/print(todo.id); // 201final user =await repository.findOne(1, params: { '_embed':'todos' });
// GET https://my-json-server.typicode.com/flutterdata/demo/users/1?_embed=todosprint(user.todos.length); // 20await user.todos.last.delete();For an in-depth example check out the Tutorial.
Fully functional app built with Flutter Data? See the code for the finished Flutter Data TO-DOs Sample App.
Fully compatible with the tools we know and love:
| Flutter | ✅ | And pure Dart, too. Null-safety coming soon! |
| Flutter Web | ✅ | Supported! |
| json_serializable | ✅ | Fully supported (but not required) |
| Riverpod | ✅ | Supported & automatically wired up |
| Provider | ✅ | Supported with minimal extra code |
| get_it | ✅ | Supported with minimal extra code |
| Classic JSON REST API | ✅ | Built-in support! |
| JSON:API | ✅ | Supported via external adapter |
| Freezed | ✅ | Supported! |
Please use Github to ask questions, open issues and send PRs. Thanks!
On Twitter: @flutterdata
Tests can be run with: pub run test
See LICENSE.
