synquill_graphql
GraphQL adapter integration for the Synquill offline-first persistent data synchronization engine.
synquill_graphql provides a robust, production-ready GraphQL API adapter capable of executing queries, mutations, and real-time subscriptions, while mapping network data directly into the local SQLite store managed by Drift.
Features
- Flexible Query Compilation: Supports both raw GraphQL query strings and fully structured AST-based
gqlNode definitions. - HTTP Query Batching: Built-in DataLoader-style batching to group multiple concurrent individual GraphQL queries into a single HTTP POST request to minimize network overhead.
- Real-Time Subscriptions: Native implementation of the modern
graphql-transport-wsprotocol over WebSockets for robust stream events. - Unified Error Handling: The
GraphQLErrorHandlingMixinintercepts GraphQL response errors (inspectingextensions.code) and translates them into typedSynquillStorageExceptionfailures (e.g.AuthenticationException,ValidationException). - Partial Success Control: Custom strategies to handle standard GraphQL hybrid responses containing both
dataanderrors. - Automatic Persistence Mapping: Automatically bridges incoming WebSocket stream events or HTTP query responses into SQLite transaction writes using Drift.
Installation
Add both the core engine and the GraphQL adapter to your Flutter project's pubspec.yaml:
dependencies:
synquill: ^0.8.3
synquill_graphql: ^0.8.2
dev_dependencies:
synquill_gen: ^0.8.3
build_runner: ^2.4.14
Quick Start
1. Create your GraphQL API Adapter
Define your GraphQL endpoints, headers, and individual resource query maps:
import 'package:synquill_graphql/synquill_graphql.dart';
mixin TodoGraphQLAdapter on GraphQLApiAdapterMixin<Todo> {
@override
Uri get baseUrl => Uri.parse('https://api.example.com/graphql');
@override
Uri get wsUrl => Uri.parse('wss://api.example.com/graphql');
@override
String get type => 'todo';
// GraphQL query string used to fetch a single item
@override
String get findOneQuery => r'''
query GetTodo($id: ID!) {
todo(id: $id) {
id
title
isCompleted
}
}
''';
// GraphQL query string used to fetch lists
@override
String get findAllQuery => r'''
query GetTodos {
todos {
id
title
isCompleted
}
}
''';
// GraphQL mutation used to create/update
@override
String get createOneMutation => r'''
mutation CreateTodo($input: TodoInput!) {
createTodo(input: $input) {
id
title
isCompleted
}
}
''';
}
2. Configure model with @SynquillRepository
Attach your newly defined GraphQL adapter mixin directly to your model repository configuration:
@JsonSerializable()
@SynquillRepository(
adapters: [GraphQLApiAdapter, TodoGraphQLAdapter],
)
class Todo extends SynquillDataModel<Todo> {
@override
final String id;
final String title;
final bool isCompleted;
Todo({required this.id, required this.title, required this.isCompleted});
// ... toJson, fromJson, and fromDb boilerplate
}
3. Consume with Reactive Watch Streams
Once code generation finishes, you can use high-level reactive streams which link local SQLite tables with remote GraphQL subscriptions seamlessly:
// Fetch database record instantly AND automatically open a WebSocket subscription to updates
final Stream<List<Todo>> activeTodos = todoRepository.watchAll(watchRemote: true);
activeTodos.listen((todos) {
// Automatically reactive to both offline database updates and remote WebSocket notifications
updateUI(todos);
});
Documentation
For deep dives into advanced configurations, check out:
- GraphQL API Adapter Detailed Guide: Features, WebSocket subscriptions, HTTP batching tuning, custom query parameters, and error mapping configurations.
- Synquill Core Documentation: Architecture overview, SQLite persistence guides, custom headers, and database migrations.
Libraries
- synquill_graphql
- A GraphQL adapter package for the Synquill offline-first data engine.