ariejan/flutter_data

Seamlessly manage persistent data in your Flutter apps

โ˜… 0Forks 0DartGitHub โ†—Compare

Project website โ†—

README

Flutter Data

tests codecov pub.dev license

Persistent reactive models in Flutter with zero boilerplate

Flutter Data is an offline-first data framework with a customizable REST client and powerful model relationships.

Inspired by Ember Data and ActiveRecord.

Features

  • Repositories for all models ๐Ÿš€
  • 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 Tutorial ๐Ÿ“š where we build a TO-DO app from the ground up in record time.

๐Ÿ‘ฉ๐Ÿพโ€๐Ÿ’ป Usage

(See the quickstart guide for setup and boot configuration.)

For a given User model annotated with @DataRepository:

@JsonSerializable()
@DataRepository([MyJSONServerAdapter])
class User extends DataModel<User> {
  @override
  final int? id; // ID can be of any type
  final String name;
  User({this.id, required this.name});
  // `User.fromJson` and `toJson` optional
}

mixin MyJSONServerAdapter on RemoteAdapter<User> {
  @override
  String get baseUrl => "https://my-json-server.typicode.com/flutterdata/demo/";
}

After a code-gen build, Flutter Data will generate a Repository<User> (and shortcuts like ref.users for Riverpod):

@override
Widget build(BuildContext context, WidgetRef ref) {
  final state = ref.users.watchOne(1);
  if (state.isLoading) {
    return Center(child: const CircularProgressIndicator());
  }
  final user = state.model;
  return Text(user.name);
}

Update the user:

TextButton(
  onPressed: () => ref.users.save(User(id: 1, name: 'Updated')),
  child: Text('Update'),
),

ref.users.watchOne(1) will make a background HTTP request (to https://my-json-server.typicode.com/flutterdata/demo/users/1 in this case), deserialize data 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.

In addition to the reactivity, DataModels get extensions and automatic relationships, ActiveRecord-style, so the above becomes:

GestureDetector(
  onTap: () => User(id: 1, name: 'Updated').save(),
  child: Text('Update')
),

More examples:

final task = await Task(title: 'Finish docs').save();
// or its equivalent:
final task = await ref.tasks.save(Task(title: 'Finish docs'));
// POST https://my-json-server.typicode.com/flutterdata/demo/tasks/
print(task.id); // 201

final user = await repository.findOne(1, params: {'_embed': 'tasks'});
// (remember repository can be accessed via ref.users)
// GET https://my-json-server.typicode.com/flutterdata/demo/users/1?_embed=tasks
print(user.tasks.length); // 20

await user.tasks.last.delete();

Explore the Documentation.

Compatibility

Fully compatible with the tools we know and love:

Flutter โœ… And pure Dart, too.
Flutter Web โœ… Supported (untested)
json_serializable โœ… Fully supported (but not required)
Riverpod โœ… Supported & automatically wired up
Classic JSON REST API โœ… Built-in support!
JSON:API โœ… Supported via external adapter
Firebase, Supabase, GraphQL โœ… Can be fully supported by writing custom adapters
Freezed โœ… Supported!

๐Ÿ“ฒ Apps using Flutter Data in production

logos

โž• Questions and collaborating

Please use Github to ask questions, open issues and send PRs. Thanks!

Tests can be run with: dart test

๐Ÿ“ License

See LICENSE.

Contributors

frank06Skycoder42ariejanandreacionif3athrubgithub

Issues