Thinking about using GraphQL but unsure where to start?
This is a concise tutorial based on our experience using GraphQL. You will learn how to use GraphQL in a Flutter app, including how to create a query, a mutation, and a subscription using the graphql_flutter plugin. Once you've mastered the fundamentals, you can move on to designing your own workflow.
Key topics and takeaways:
* What is graphql_flutter?
* Setting up graphql_flutter and GraphQLProvider
Looking to call multiple endpoints to populate data for a single screen? Wish you had more control over the data returned by the endpoint? Is it possible to get more data with a single endpoint call, or does the call only return the necessary data fields?
Follow along to learn how to do this with GraphQL. GraphQL’s goal was to change the way data is supplied from the backend, and it allows you to specify the data structure you want.
Let's imagine that we have the table model in our database that looks like this:
These fields represent the properties of the Movie Model:
- title property is the name of the Movie,
- genre describes what kind of movie
- rating represents viewers interests
- year states when it is released
We can get movies like this using REST:
As you can see, whether or not we need them, REST returns all of the properties of each movie. In our frontend, we may just need the title and genre properties, yet all of them were returned.
We can avoid redundancy by using GraphQL. We can specify the properties we wish to be returned using GraphQL, for example:
We're informing the server that we only require the movie table's title and genre properties. It provides us with exactly what we require:
GraphQL is a backend technology, whereas Flutter is a frontend SDK for developing mobile apps. We get the data displayed on the mobile app from a backend when we use mobile apps.
It's simple to create a Flutter app that retrieves data from a GraphQL backend. Simply make an HTTP request from the Flutter app, then use the returned data to set up and display the UI.
The new graphql_flutter plugin includes APIs and widgets for retrieving and using data from GraphQL backends.
What is graphql_flutter?
The new graphql_flutter plugin includes APIs and widgets that make it simple to retrieve and use data from a GraphQL backend.
graphql_flutter, as the name suggests, is a GraphQL client for Flutter. It exports widgets and providers for retrieving data from GraphQL backends, such as:
- HttpLink — This is used to specify the backend's endpoint or URL.
- GraphQLClient — This class is used to retrieve a query or mutation from a GraphQL endpoint as well as to connect to a GraphQL server.
- GraphQLCache — We use this class to cache our queries and mutations. It has an options store where we pass the type of store to it during its caching operation.
- GraphQLProvider — This widget encapsulates the graphql flutter widgets, allowing them to perform queries and mutations. This widget is given to the GraphQL client to use. All widgets in this provider's tree have access to this client.
- Query — This widget is used to perform a backend GraphQL query.
- Mutation — This widget is used to modify a GraphQL backend.
- Subscription — This widget allows you to create a subscription.
Setting up graphql_flutter and GraphQLProvider
Create a Flutter project:
Next, install the graphql_flutter package:
The code above will set up the graphql_flutter package. This will include the graphql_flutter package in the dependencies section of your pubspec.yaml file:
To use the widgets, we must import the package as follows:
Before we can start making GraphQL queries and mutations, we must first wrap our root widget in GraphQLProvider. A GraphQLClient instance must be provided to the GraphQLProvider's client property.
The GraphQLClient includes the GraphQL server URL as well as a caching mechanism.
HttpLink is used to generate the URL for the GraphQL server. The GraphQLClient receives the instance of the HttpLink in the form of a link property, which contains the URL of the GraphQL endpoint.
The cache passed to GraphQLClient specifies the cache mechanism to be used. To persist or store caches, the InMemoryCache instance makes use of an in-memory database.
A GraphQLClient instance is passed to a ValueNotifier. This ValueNotifer holds a single value and has listeners that notify it when that value changes. This is used by graphql_flutter to notify its widgets when the data from a GraphQL endpoint changes, which helps graphql_flutter remain responsive.
We'll now encase our MaterialApp widget in GraphQLProvider:
We'll use the Query widget to create a query with the graphql_flutter package.
The Query widget encloses the ListView widget, which will display the list of counters to be retrieved from our GraphQL server. As a result, the Query widget must wrap the widget where the data fetched by the Query widget is to be displayed.
The Query widget cannot be the tree's topmost widget. It can be placed wherever you want as long as the widget that will use its data is underneath or wrapped by it.
In addition, two properties have been passed to the Query widget: options and builder.
The option property is where the query configuration is passed to the Query widget. This options prop is a QueryOptions instance. The QueryOptions class exposes properties that we use to configure the Query widget.
The query string or the query to be conducted by the Query widget is set or sent in via the document property. We passed in the readCounters string here:
The variables attribute is used to send query variables to the Query widget. There is a 'counterId': 23 there. In the readCounters query string, this will be passed in place of $counterId.
The pollInterval specifies how often the Query widget polls or refreshes the query data. The timer is set to 10 seconds, so the Query widget will perform HTTP requests to refresh the query data every 10 seconds.
A function is the builder property. When the Query widget sends an HTTP request to the GraphQL server endpoint, this function is called. The Query widget calls the builder function with the data from the query, a function to re-fetch the data, and a function for pagination. This is used to get more information.
The builder function returns widgets that are listed below the Query widget. The result argument is a QueryResult instance. The QueryResult class has properties that can be used to determine the query's current state and the data returned by the Query widget.
- If the query encounters an error, QueryResult.hasException is set.
- If the query is still in progress, QueryResult.isLoading is set. We can use this property to show our users a UI progress bar to let them know that something is on its way.
- The data returned by the GraphQL endpoint is stored in QueryResult.data.
Let's look at how to make mutation queries with the Mutation widget in graphql_flutter.
The Mutation widget is used as follows:
The Mutation widget, like the Query widget, accepts some properties.
- options is a MutationOptions class instance. This is the location of the mutation string and other configurations.
- The mutation string is set using a document. An addCounter mutation has been passed to the document in this case. The Mutation widget will handle it.
- When we want to update the cache, we call update. The update function receives the previous cache (cache) and the outcome of the mutation. Anything returned by the update becomes the cache's new value. Based on the results, we're refreshing the cache.
- When the mutations on the GraphQL endpoint have been called, onCompleted is called. The onCompleted function is then called with the mutation result builder to return the widget from the Mutation widget tree. This function is invoked with a RunMutation instance, runMutation, and a QueryResult instance result.
- The Mutation widget's mutation is executed using runMutation. The Mutation widget causes the mutation whenever it is called. The mutation variables are passed as parameters to the runMutation function. The runMutation function is invoked with the counterId variable, 21.
When the Mutation's mutation is finished, the builder is called, and the Mutation rebuilds its tree. runMutation and the mutation result are passed to the builder function.
Subscriptions in GraphQL are similar to an event system that listens on a WebSocket and calls a function whenever an event is emitted into the stream.
The client connects to the GraphQL server via a WebSocket. The event is passed to the WebSocket whenever the server emits an event from its end. So this is happening in real-time.
The graphql_flutter plugin in Flutter uses WebSockets and Dart streams to open and receive real-time updates from the server.
Let's look at how we can use our Flutter app's Subscription widget to create a real-time connection. We'll start by creating our subscription string:
When we add a new counter to our GraphQL server, this subscription will notify us in real-time.
The Subscription widget has several properties, as we can see:
- options holds the Subscription widget's configuration.
- document holds the subscription string.
- builder returns the Subscription widget's widget tree.
The subscription result is used to call the builder function. The end result has the following properties:
- If the Subscription widget encounters an error while polling the GraphQL server for updates, result.hasException is set.
- If polling from the server is active, result.isLoading is set.
The provided helper widget ResultAccumulator is used to collect subscription results, according to graphql_flutter's pub.dev page.
This blog intends to help you understand what makes GraphQL so powerful, how to use it in Flutter, and how to take advantage of the reactive nature of graphql_flutter. You can now take the first steps in building your applications with GraphQL!