# GraphQL in Flutter - Building a Mobile Shop using Saleor API
This tutorial will show you how to create a simple mobile app in [Flutter](https://flutter.dev) on top of the Saleor API that exchanges the data using GraphQL. Along with some basic styling. Our goal is to show you how to create a **mobile basis** of an e-commerce app in Flutter.
## Introduction
[GraphQL](https://graphql.org) is a query language and server-side runtime for APIs. It is able to provide a complete and convenient description of the data in your API. The query language allows clients to form the data requests for exact shape of the data they need. GraphQL is designed to make APIs flexible and convenient to use so that they are easier to evolve and maintain. GraphQL helps you keep up with the growing compelixty of apps.
GraphQL has many advantages compared to REST. Instead of using a fixed data structure approach, GraphQL requests specific data the client's needs. REST responses are notorious for containing too much data or not enough. GraphQL solves this by fetching exact data in a single request. GraphQL also has an introspection feature which allows developers to check types & the schema to ensure they're asking for data the right way.
Saleor is an all-in-one platform for creating production-grade shopping experience on the Internet. Saleor exposes a comprehensive set of e-commerce notions as a GraphQL endpoint. Building digital shops used to be complex. Nowdays you can relay on specialist solutions such as Saleor providing consolidated e-commerce knowledge that expose it in an easy-to-use manner. Saleor allows you to manage any number of storefronts such as web or mobile apps from a single back-end.
In this tutorial we will build a mobile app on top of the Saleor GraphQL API using the Flutter framework. Flutter is an open-source user interface toolkit created by Google. It's become an increasingly popular tool because it's a cross-platform solution. Flutter allows you to use one programming language and one code base to target different platforms such iOS, Android, Deskop and the browser at once. This means you no longer need to learn different languages to target specific platforms with your apps.
## Prerequisites
Before you begin this guide, you’ll need the following:
- Basic understanding of mobile app development
- Dart & Flutter (follow [the official installation guide](https://flutter.dev/docs/get-started/install))
- [VS Code](https://code.visualstudio.com) as the editor
# Getting Started
Let’s start by creating a Flutter application inside VS Code. Make sure you have Flutter and Dart installed along with [their VS Code extensions](https://flutter.dev/docs/development/tools/vs-code). Then, press `CTRL + SHIFT + P` to open the VS Code command palette. Use the command `Flutter: New Application Project`. This will give you a basic boilerplate to work with.
Name it whatever you would like and you should be good to go.
Run the phone simulator and start the app to make sure it works as expected. On MacOS you can use the simulator that comes with Xcode. For other operating systems, refer to [the Flutter documentation](https://flutter.dev/docs/get-started/install) for details. The boilerplate comes with a simple counting app. It should look something like this.

# Installing the Libraries & Dependencies
First, we’re going to add [`graphql_flutter`](https://pub.dev/packages/graphql_flutter) to our project. This is a GraphQL client for Flutter that brings all the features from a modern GraphQL client to one easy to use package. It also combines the benefits of GraphQL with the benefits of Streams in Dart to deliver a high-performance client.
Go inside the `pubspec.yaml` file at the base of the project. Find the line `cupertino_icons`. Right below it, add the following.
``
graphql_flutter:
``
Save the file. Your project will automatically find the latest version. You can make sure it did so by going into pubspec.lock file and finding the graphql_flutter version. Currently, `5.0.0` is the latest stable version.
# Removing the Boilerplate
Now that everything is set up, we can remove the increment counter and some comments in our project. Your `main.dart` file should look something like this.
```dart
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(),
);
}
}
```
We can now start getting our data from the Saleor GraphQL endpoint.
# Your First Query
At the top of the `main.dart` file under the `import` statement, define the `productsGraphQL` variable that will hold the follwing GraphQL query as a string:
```graphql
query products {
products(first: 10) {
edges {
node {
id
name
description
thumbnail {
url
}
}
}
}
}
```
Typically, you would want to have separate files for each query. But for the sake of this tutorial, we’re going to keep everything inside our `main.dart` file.
Next, we’re going to write an integration and create the GraphQL client. We’re also going to wrap our client inside a value notifier.
```dart
void main() {
final HttpLink httpLink = HttpLink("https://demo.saleor.io/graphql/");
ValueNotifier<GraphQLClient> client = ValueNotifier(
GraphQLClient(
link: httpLink,
cache: GraphQLCache(store: InMemoryStore()),
),
);
runApp(MyApp());
}
```
Our `client` must be then provided to the application widget tree using the `GraphQLProvider` class. Again, this isn’t the way you’d want to write code for production. But it will be enough for this tutorial.
```dart
void main() {
final HttpLink httpLink = HttpLink("https://demo.saleor.io/graphql/");
ValueNotifier<GraphQLClient> client = ValueNotifier(
GraphQLClient(
link: httpLink,
cache: GraphQLCache(store: InMemoryStore()),
),
);
var app = GraphQLProvider(client: client, child: MyApp());
runApp(app);
}
```
If you run this app, it will be completely empty. You have to explicitly specify the data in the query response that we want to disply. Go into the `_MyHomePageState` class at the bottom of the file and use the `Query` widget as the child in the position of the `body:` parameter.
```dart
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Query(
options: QueryOptions(
document: gpl(productsGraphQL),
),
builder: (QueryResult result, {fetchMore, refetch}) {
if (result.hasException) {
return Text(result.exception.toString());
}
if (result.isLoading) {
return Center(
child: CircularProgressIndicator(),
);
}
final productList = result.data?['products']['edges'];
print(productList);
return Text("Something");
},
),
);
}
}
```
In the `Query` widget, we’re going to use two parameters: `options` and `builder`. For `options`, we’re going to use `QueryOptions` which will use the variable holding the GraphQL query as string that we created earlier, i.e. `productsGraphQL`, wrapped inside a helper function.
For the builder, we will have `QueryResult`. We will create a check to see if there was an exception or not. We’ll also include an if-statement to display a circular progress indicator while the data fetching is in progress.
If our data loads properly, we’re going to extract the proper fields. And for now, we’ll simply print the data to our debug console.
You should see the word “something” displayed in your app and the products from the query inside your debug console.
Now that we know we can fetch data properly, we can start displaying those products in our app. We’re also going to be adding some simple styling to keep our app looking fresh. Our products will be arranged in a 2-column grid. We will use the `GridView` widget for that. Its `itemBuilder` gets each product that we fetched using our GraphQL query within the `Query` widget and then we extract the product image and name to display it.
Edit the `return` statement to display the products.
```dart
return Column(
children: [
Padding(
padding: EdgeInsets.all(16.0),
child: Text(
"Products",
style: Theme.of(context).textTheme.headline5,
),
),
Expanded(
child: GridView.builder(
itemCount: productList.length,
gridDelegate: SilverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 2.0,
crossAxisSpacing: 2.0,
childAspectRatio: 0.75,
), // SilverGridDelegateWithFixedCrossAxisCount
itemBuilder: (_, index) {
var product = productList[index]['node'];
return Column(
children: [
Container(
padding: EdgeInsets.all(2.0),
width: 180,
height: 180,
child: Image.network(product['thumbnail']['url']),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 8.0),
child: Text(
product['name'],
style: TextStyle(fontWeight: FontWeight.bold),
),
),
Text("\$4.50")
],
);
}
)
)
],
);
```
Also, keep in mind we are hard-coding the price because we didn’t include that in our query. All our items in our shop will have the same price as a result.
And with that, your app should be displaying the products. It should look something like this.

You should see a centered title, all the products, and the hard-coded price for each of them.
And that’s going to be it. You did it!
## Next Steps
As an excercise, try to modify the GraphQL query to include the real price. You can start from the GraphQL playground. Use the `docs` tab to explore possible parameters of a query. The query we use is called `products`. Find it and identify which fields are needed to get the price of each product as the response.
## Conclusion
In this tutorial, we created a simple mobile application using the Flutter framework. We integrated with a GraphQL endpoint using the `graphql_flutter` package. Finally we used the Saleor API as the GraphQL endpoint with a query for fetching a list of products. We finished off by displaying the results to the user.
If you had any problems with finishing this tutorial, let us know on [GitHub Discussions](https://github.com/mirumee/saleor/discussions). We'd be happy to help!
The code is available on our GitHub.