graphql_flutter 1.0.0-alpha.4 graphql_flutter: ^1.0.0-alpha.4 copied to clipboard
A GraphQL client for Flutter, bringing all the features from a modern GraphQL client to one easy to use package.
GraphQL Flutter #
Table of Contents #
About this project #
GraphQL brings many benefits, both to the client: devices will need less requests, and therefore reduce data useage. And to the programer: requests are arguable, they have the same structure as the request.
This project combines the benefits of GraphQL with the benefits of Streams
in Dart to deliver a high performace client.
The project took inspriation from the Apollo GraphQL client, great work guys!
Installation #
First depend on the library by adding this to your packages pubspec.yaml
:
dependencies:
graphql_flutter: ^1.0.0-alpha
Now inside your Dart code you can import it.
import 'package:graphql_flutter/graphql_flutter.dart';
Upgrading from 0.x.x #
Here is a guide to fix most of the breaking changes introduced in 1.x.x.
Some class names have been renamed:
- Renamed
Client
toGraphQLClient
- Renamed
GraphqlProvider
toGraphQLProvider
- Renamed
GraphqlConsumer
toGraphQLConsumer
- Renamed
GQLError
toGraphQLError
We changed the way the client handles requests, it now uses a Link
to execute queries rather then depend on the http package. We've currently only implplemented the HttpLink
, just drop it in like so:
void main() {
+ HttpLink link = HttpLink(
+ uri: 'https://api.github.com/graphql',
+ headers: <String, String>{
+ 'Authorization': 'Bearer <YOUR_PERSONAL_ACCESS_TOKEN>',
+ },
+ );
- ValueNotifier<Client> client = ValueNotifier(
+ ValueNotifier<GraphQLClient> client = ValueNotifier(
- Client(
- endPoint: 'https://api.github.com/graphql',
+ GraphQLClient(
cache: InMemoryCache(),
- apiToken: '<YOUR_GITHUB_PERSONAL_ACCESS_TOKEN>',
+ link: link,
),
);
}
We have made a load of changes how queries and mutations work under the hood. To allow for these changes we had to make some small changes to the API of the Query
and Mutation
widgets.
Query(
- readRepositories,
+ options: QueryOptions(
+ document: readRepositories,
variables: {
'nRepositories': 50,
},
pollInterval: 10,
+ ),
- builder: ({
- bool loading,
- var data,
- String error,
- }) {
+ builder: (QueryResult result) {
- if (error != '') {
- return Text(error);
+ if (result.errors != null) {
+ return Text(result.errors.toString());
}
- if (loading) {
+ if (result.loading) {
return Text('Loading');
}
- List repositories = data['viewer']['repositories']['nodes'];
+ List repositories = result.data['viewer']['repositories']['nodes'];
return ListView.builder(
itemCount: repositories.length,
itemBuilder: (context, index) {
final repository = repositories[index];
return Text(repository['name']);
});
},
);
Mutation(
- addStar,
+ options: MutationOptions(
+ document: addStar,
+ ),
builder: (
- runMutation, {
- bool loading,
- var data,
- String error,
+ RunMutation runMutation,
+ QueryResult result,
- }) {
+ ) {
return FloatingActionButton(
onPressed: () => runMutation({
'starrableId': <A_STARTABLE_REPOSITORY_ID>,
}),
tooltip: 'Star',
child: Icon(Icons.star),
);
},
);
That's it! You should now be able to use the latest version of our library.
Usage #
To use the client it first needs to be initialized with an link and cache. For this example we will be uing an HttpLink
as our link and InMemoryCache
as our cache. If your endpoint requires authentication you can provide some custom headers to HttpLink
.
For this example we will use the public GitHub API.
...
import 'package:graphql_flutter/graphql_flutter.dart';
void main() {
HttpLink link = HttpLink(
uri: 'https://api.github.com/graphql',
headers: <String, String>{
'Authorization': 'Bearer <YOUR_PERSONAL_ACCESS_TOKEN>',
},
);
ValueNotifier<GraphQLClient> client = ValueNotifier(
GraphQLClient(
cache: InMemoryCache(),
link: link,
),
);
...
}
...
GraphQL Provider #
In order to use the client, you Query
and Mutation
widgets to be wrapped with the GraphQLProvider
widget.
We recommend wrapping your
MaterialApp
with theGraphQLProvider
widget.
...
return GraphQLProvider(
client: client,
child: MaterialApp(
title: 'Flutter Demo',
...
),
);
...
Offline Cache #
The in-memory cache can automatically be saved to and restored from offline storage. Setting it up is as easy as wrapping your app with the CacheProvider
widget.
It is required to place the
CacheProvider
widget is inside theGraphQLProvider
widget, becauseGraphQLProvider
makes client available trough the build context.
...
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GraphQLProvider(
client: client,
child: CacheProvider(
child: MaterialApp(
title: 'Flutter Demo',
...
),
),
);
}
}
...
Queries #
Creating a query is as simple as creating a multiline string:
String readRepositories = """
query ReadRepositories(\$nRepositories) {
viewer {
repositories(last: \$nRepositories) {
nodes {
id
name
viewerHasStarred
}
}
}
}
"""
.replaceAll('\n', ' ');
In your widget:
...
Query(
options: QueryOptions(
document: readRepositories, // this is the query string you just created
variables: {
'nRepositories': 50,
},
pollInterval: 10,
),
builder: (QueryResult result) {
if (result.errors != null) {
return Text(result.errors.toString());
}
if (result.loading) {
return Text('Loading');
}
// it can be either Map or List
List repositories = result.data['viewer']['repositories']['nodes'];
return ListView.builder(
itemCount: repositories.length,
itemBuilder: (context, index) {
final repository = repositories[index];
return Text(repository['name']);
});
},
);
...
Mutations #
Again first create a mutation string:
String addStar = """
mutation AddStar(\$starrableId: ID!) {
addStar(input: {starrableId: \$starrableId}) {
starrable {
viewerHasStarred
}
}
}
"""
.replaceAll('\n', ' ');
The syntax for mutations is fairly similar to that of a query. The only diffence is that the first argument of the builder function is a mutation function. Just call it to trigger the mutations (Yeah we deliberately stole this from react-apollo.)
...
Mutation(
options: MutationOptions(
document: addStar, // this is the mutation string you just created
),
builder: (
RunMutation runMutation,
QueryResult result,
) {
return FloatingActionButton(
onPressed: () => runMutation({
'starrableId': <A_STARTABLE_REPOSITORY_ID>,
}),
tooltip: 'Star',
child: Icon(Icons.star),
);
},
);
...
Subscriptions (Experimental) #
The syntax for subscriptions is again similar to a query, however, this utilizes WebSockets and dart Streams to provide real-time updates from a server.
Before subscriptions can be performed a global intance of socketClient
needs to be initialized.
We are working on moving this into the same
GraphQLProvider
stucture as the http client. Therefore this api might change in the near future.
socketClient = await SocketClient.connect('ws://coolserver.com/graphql');
Once the socketClient
has been initialized it can be used by the Subscription
Widget
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Subscription(
operationName,
query,
variables: variables,
builder: ({
bool loading,
dynamic payload,
dynamic error,
}) {
if (payload != null) {
return Text(payload['requestSubscription']['requestData']);
} else {
return Text('Data not found');
}
}
),
)
);
}
}
Graphql Consumer #
You can always access the client direcly from the GraphQLProvider
but to make it even easier you can also use the GraphQLConsumer
widget.
...
return GraphQLConsumer(
builder: (GraphQLClient client) {
// do something with the client
return Container(
child: Text('Hello world'),
);
},
);
...
Roadmap #
This is currently our roadmap, please feel free to request additions/changes.
Feature | Progress |
---|---|
Queries | ✅ |
Mutations | ✅ |
Subscriptions | ✅ |
Query polling | ✅ |
In memory cache | ✅ |
Offline cache sync | ✅ |
Optimistic results | 🔜 |
Client state management | 🔜 |
Modularity | 🔜 |
Contributing #
Feel free to open a PR with any suggestions! We'll be actively working on the library ourselves.
Contributors #
This package was originally created and published by the engineers at Zino App BV. Since then the community has helped to make it even more useful for even more developers.
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind are welcome!