Exploring GraphQL with Flutter 
Tags: flutter, graphql, dart
Published: 2019-06-09 05:23:49

In this Blog post, Let's discuss **Various way available to implement GraphQL with Flutter** 

##First of all, What's this GraphQL?

We are not going in depth about the concept of GraphQL in the post, but here is the short description from an official document

*GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.* 

GraphQL is developed and now open sourced by the tech team of Facebook, which is a different way to implement APIs in your application. *Let's see how we implement this with Flutter*

##How I will manage this on Flutter?

While you can use normal HTTP GET request to execute Graph Query, Flutter has some cool pubs available which manage this stuffs and make developer's job easy.

If you look for GraphQL client for Flutter, there are good options available like [graphql_flutter](https://pub.dev/packages/graphql_flutter#-readme-tab-).

graphql_flutter pub provides a Widget level implementation for Graph Query.
For Example:

``` dart
Query(
  options: QueryOptions(
    document: readRepositories, // this is a Graph Query
    variables: {
      'nRepositories': 50,
    },
    pollInterval: 10,
  ),
  builder: (QueryResult result, { VoidCallback refetch }) {
    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']);
    });
  },
);
```

This is a very high-level widget implementation which will manage the networking from Widget itself.
 
##But, How I will separate the Network layer in my App? 🤷

Yes!, This is what we also questioned. As we are using BLoC architecture in one of our Flutter application, this implementation was surely not granular to suits.

To answer this question, We analyzed the internal implementation of this pub. Here is the outcome.

##Implement GraphQL on BLoC way

Here is a nice pub available [graphql_client](https://pub.dev/packages/graphql). This is the same pub which has been used underlying by [graphql_flutter](https://pub.dev/packages/graphql_flutter#-readme-tab-). By this, we should be able to separate a network layer in App

Let us take an example of [Github Graph API](https://developer.github.com/v4/)

Let's dive into the code directly
* Step 1: Basic Setup

``` dart
//Provide a Base URL
final HttpLink _httpLink = HttpLink(
  uri: 'https://api.github.com/graphql',
);

//Provide authentication, this will go as a Header in Request
final AuthLink _authLink = AuthLink(
  getToken: () async => 'Bearer $GITHUB_TOKEN',
);

final Link _link = _authLink.concat(_httpLink as Link);

GraphQLClient _client;

// Create a common client for further requests
GraphQLClient getGraphQLClient() {
  _client ??= GraphQLClient(
    link: _link,
    cache: InMemoryCache(storageProvider: () {
      return getTemporaryDirectory(); // Provide a cache mechanism
    }),
  );

  return _client;
}
```

* Step 2: Repository Layer

``` dart
class GitHubRepoProvider {
// method will give us Data model
  Future<List<GithubRepo>> getCurrentUserRepos() {
    return getGraphQLClient().query(_queryOptions()).then(_toGitHubRepo);
  }

// provides Graph Query options, we can provide the optional variable here
  QueryOptions _queryOptions() {
    return QueryOptions(
      document: readRepositories,
      variables: <String, dynamic>{
        'nRepositories': 50,
      },
    );
  }

// parse JSON to Data model
  List<GithubRepo> _toGitHubRepo(QueryResult queryResult) {
    if (queryResult.hasErrors) {
      throw Exception();
    }

    final list =
        queryResult.data['viewer']['repositories']['nodes'] as List<dynamic>;

    return list
        .map((repoJson) => GithubRepo.fromJson(repoJson))
        .toList(growable: false);
  }
}

// Graph Query to get repository of current user
const String _readRepositories = r'''
  query ReadRepositories($nRepositories: Int!) {
    viewer {
      repositories(last: $nRepositories) {
        nodes {
          name
          createdAt
          forkCount
        }
      }
    }
  }
''';
```

Bingo 👍. We now have a Data model. Covert your DataModel into ViewModel from the BLoC 😉

You can see the full working demo Application here 👇. (Don't forget to edit `config.dart` file to add your Github API token)

{% github milind-mevada-stl/Flutter-GraphQL-Demo %}


Provide your ideas/suggestions in the comment section or hit me a tweet 👉 
{% twitter 1134034323772887040 %}