GraphQL with Flutter

GraphQL with Flutter

ยท

4 min read

Let's talk about how to integrate GraphQL with Flutter step by step.

Need to add this dependency in pubspec.yaml file.

dependencies:
  graphql_flutter: ^5.1.2

In main.dart file:

WidgetsFlutterBinding.ensureInitialized();
  await initHiveForFlutter();

Under void main() write the above code.

Configuration

Create a class with a name of your choice. In this class we will write the configuration code. Here we will create 2 links. These links are the URLs where we will send the requests.

static HttpLink link = HttpLink("http://192.168.29.150/graphql");

  late Link authLink;

  Link setAuthLink() {
    authLink = HttpLink("http://192.168.29.150/graphql",
        defaultHeaders: {'Authorization': 'Bearer $a'});
    return authLink;
  }
  1. The first link ( link ) is the link without headers.

  2. The second link (authLink) is the link with headers.

Creating the clients:

getGQLClent() {
    GraphQLClient qlClient = GraphQLClient(
      // craete a graphql client
      link: link,
      cache: GraphQLCache(
        store: HiveStore(),
      ),
    );
    return qlClient;
  }

  getGQLAuthClient() {
    GraphQLClient qlClientAuth = GraphQLClient(
      // craete a graphql client
      link: setAuthLink(),
      cache: GraphQLCache(
        store: HiveStore(),
      ),
    );

    return qlClientAuth;
  }

These are the 2 methods that create GraphQL clients.

The first method (getGQLClent()) creates the client with the link without headers. The second method (getGQLAuthClient()) creates the client with the link with headers.

import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:todo_graphql_app/local_storage.dart';
import 'package:todo_graphql_app/utils/local_storage.dart';

class Util {
  var a = localStorageNew.getString('token');

  static HttpLink link = HttpLink("http://192.168.29.150/graphql");

  late Link authLink;

  Link setAuthLink() {
    authLink = HttpLink("http://192.168.29.150/graphql",
        defaultHeaders: {'Authorization': 'Bearer $a'});
    return authLink;
  }


  static GraphQLClient qlClient = GraphQLClient(
    // craete a graphql client
    link: link,
    cache: GraphQLCache(
      store: HiveStore(),
    ),
  );

  getGQLClent() {
    GraphQLClient qlClient = GraphQLClient(
      // craete a graphql client
      link: link,
      cache: GraphQLCache(
        store: HiveStore(),
      ),
    );
    return qlClient;
  }

  getGQLAuthClient() {
    GraphQLClient qlClientAuth = GraphQLClient(
      // craete a graphql client
      link: setAuthLink(),
      cache: GraphQLCache(
        store: HiveStore(),
      ),
    );

    return qlClientAuth;
  }
}

The whole class looks like this where I have created the links and the clients.

Next, you need to make API requests using the clients.

API Calls:

Mutations:

class LoginRepository {
  Util util = Util();
  Future<void> login(String? email, String? password) async {
    //SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
    try {
      QueryResult result = await util.getGQLClent().mutate(
            MutationOptions(
              fetchPolicy: FetchPolicy.networkOnly,
              document: gql('''
     mutation LoginUser(\$email: String!, \$password: String!) {
  loginUser(email: \$email, password: \$password) {
    token
  }
}
'''),
              variables: {"email": email, "password": password},
            ),
          );
      print('result: $result');
      if (result.hasException) {
        throw Exception(result.exception);
      } else {
        String token = result.data?["loginUser"]["token"];
        print('token: $token');
        localStorageNew.setString('token', token);

        print('success from repo');
      }
    } catch (error) {
      print('failed from repo');

      throw Exception('something went wrong!!');
    }
  }
}

Here inside try catch, using getGQLClent().mutate() we are doing mutations i.e. post request(in this case). The whole code is pretty explanatory on its own.

getGQLClent() is used here because we need the link without headers.

You can find the variables used in the mutation/query in the Apollo Server(Apollo Sandbox).

If the result has exception it will throw error, or else we will get the data. If anything goes wrong with the API call, it will go to the catch block.

Query:

Future<List> fetchToDos() async {
    try {
      QueryResult result = await util.getGQLAuthClient().query(
          QueryOptions(fetchPolicy: FetchPolicy.networkOnly, document: gql('''
query GetTodosByUser {
  getTodosByUser {
    id
    description
    title
  }
}

''')));

      if (result.hasException) {
        throw Exception(result.exception);
      }

      List res = result.data?["getTodosByUser"];

      if (res == null || res.isEmpty) {
        return [];
      } else {
        todos = res
            .map<Todo>((item) => Todo(
                description: item["description"],
                id: item["id"],
                title: item["title"]))
            .toList();
        return todos;
      }
    } catch (error) {
      print('error from repo');
      throw Exception('Something went wrong');
    }
  }

Here inside try catch, using getGQLAuthClient().query() we are doing query i.e. get request(in this case). The whole code is pretty explanatory on its own.

getGQLAuthClient() is used here because we need the link with headers.

Key takeaways:

  • graphql_flutter package is important.

  • Initial configuration and specifying the links are important.

  • Making mutations and queries as per requirement is important.

  • You can find the variables used in the mutation/query in the Apollo Server(Apollo Sandbox).

I have made a sample Todo app with GraphQL and Flutter using Riverpod. You can find the whole code here for your reference.

That's it. I hope it was worthy of your time and helped you in some way. Can you please share it with the community? Would appreciate it. Please provide your feedback in the comments. Thanks for reading.

ย