GraphQL in Flutter: Learn By Doing

Flutter is taking the world by storm and this comes as no surprise. It offers unmatched performance and robust multi-platform support. In this article, I will walk you through integrating GraphQL into Flutter Apps, making queries, and performing mutations.

What Is GraphQL?

graphql flutter

GraphQL is a query language, developed by Facebook. It is supposed to replace REST as a mean of API communication. I will assume some basic knowledge of GraphQL for the REST (pun intended) of the article. If you have not heard of it, I strongly suggest you read this article first.

Server Setup

Developing a GraphQL API is out of scope of this article. Instead, we will use a pre-made one. Head out to the repo and clone it. I have forked this server from @haikyuu, many thanks to you.

Once you have it cloned, open it in terminal and run:

npm i
npm start

This will install all dependencies and start the server. This server is a basic TODO app backend, it lets you create, query and modify tasks. It is built using json-graphql-server, be sure to check it out.

Project Setup

After we got the server up and running, lets set up the Flutter project. This is not an introductory tutorial, and if you have never used Flutter, read this article first. After you have created the project, the directory structure should look like this:

graphql flutter

If you try to run the app, this should happen in the emulator:

graphql flutter

Congratulations, we are halfway there!

Add GraphQL dependencies

Before we start working with GraphQL in our Flutter app, we need to install some dependencies. Open the pubspec.yaml file and add this line in it (in dependencies section:

graphql_flutter: ^3.0.0

Now, install the packages using this command:

flutter pub get

In a few seconds, the dependencies should install.

Write some queries

As you know, you talk to GraphQL APIs using queries. We are going to need 3 of them: a query to get a list of all tasks, a mutation to create new ones, and a mutation to complete an existing one. Create a file api.dart in /lib and put this code in it:

Firstly, note the imports on lines 1-2. The first one is a core flutter package that propagates updates down to components. The second one is the graphql_flutter package we installed earlier.

On lines 4-9 we create a GraphQL client. It will be used to access our API. The link is using the address http://10.0.2.2:3000 because this is the IP of the host computer from inside of the emulator. If you are running the app on a physical device, you need to replace this address with the local IP address of your PC (or use something like ngrok).

Lastly, we have queries. The first one is pretty straightforward: get all queries with fields id, title, and completed. createTaskMutation is a mutation to create tasks (obviously!) and it accepts 2 parameters: the id of the newly created task and its title. The backend we are using will not check for id uniqueness, due to its simplicity. The last query will update the completed field on a task with id.

There were no changes to the UI yet, so the app should look the same.

Set up the UI

All we have left now is to bind it to the UI. I will not explain the UI in depth, as you are expected to know the basics, instead, I will focus on how it interacts with GraphQL. Firstly, replace all code in main.dart with this:

The first thing you should notice is the GraphQLProvider on line 11. By wrapping the whole application in it, we provide the rest of the widgets with the GraphQL client. This means we can run queries and mutations from anywhere in the app.

Now, examine the build function of the _ListPageState class on line 75. Here, we are using the Query widget to run the query and pass the results to its children. Query accepts a options argument of type QueryOptions, which set up the query. The gql(getTasksQuery) will parse the query and pollInterval: 1 means that this query will refresh every second (this is highly inefficient, but will do for now).

Query will pass the QueryResult and the refetch and fetchMore functions to its builder callback. QueryResult has fields loading and hasException, which we use to determine what to render (lines 85-90). refetch will re-run the query if we call it, and we do, each time user toggles a task (also highly inefficient). fetchMore is used when implementing pagination, but we will leave it for now.

Now, look at the TaskList widget, specifically, its build function. It is wrapped with the Mutation class, which works pretty much like Query. The main difference is that Mutation does not automatically execute the mutation. It will pass RunMutation to its builder function that must be called to execute the mutation. You can see it in action on line 121. It accepts a map with arguments for the mutation (id and completed, in this case). We then call onRefresh to re-run the query and get updated data.

Lastly, the function onCreate on line 33 is responsible for showing a dialog to ask for the task title and creating the task itself. The AlertDialog is wrapped in now familiar Mutation and line 63 calls the mutation itself. Now we are passing id and title, the completed is false by default.

This is how the app should look:

graphql flutter

If you got lost at any point, the Github repo is available here.

Closing notes

Thank you for reading, I hope now you know how to use GraphQL in Flutter. In my coming posts I will go into performance optimizations and real-time updating. Stay tuned!

Resources

Get new content delivered to your mailbox:

leave a comment