GraphQL and Flutter step by step guide

Photo by Isaac Smith on Unsplash

GraphQL: get exactly what you need and nothing more

Let’s look at two scenarios:

  • getUser API returns a bunch of irrelevant data where you just need an email address

This is where GraphQL can be useful, in this article, I will demo how to create a GraphQL server and a Flutter Client step by step. As an app developer, you might wonder why would I care about the server? Can’t I just download the repo? In fact by the nature of GraphQL, it is highly likely that front-end engineers will be maintaining and updating the server side, so understand the basics helps.

Apollo GraphQL Server

package.json

Create a package.json file under the project root, this file contains the project configuration data and dependencies, it looks like this:

{  "name": "graphql-server",  "version": "1.0.0",  "main": "app.js",  "scripts": {...},  "dependencies": {    "apollo-datasource-http": "^0.10.0",...  }}

Datasource

There are few ways to fetch data in GraphQL: fetch from a REST api, fetch from a GraphQL api, fetch from a database, and that is done via data source. This is where you can reduce a good amount of api calls and combine them into one. Let’s say we need to make one api call to get user and one to get a list of items, then we need to create two separate data course file:

const userdata = new (class UserAPI extends HTTPDataSource {  constructor() {       const pool = new Pool("http://localhost:8080/");       super(baseURL, {pool})
}
async getUser(userID) { return this.get(`/company/${userID}`, {});
}})
module.exports = userdata

Second data source file to fetch list of items

//second data source file to fetch list of items
const listdata = new (class UserAPI extends HTTPDataSource {
constructor() { const pool = new Pool("http://localhost:8080/"); super(baseURL, {pool})
}
async getList(itemID) { return this.get(`/list`, {query: {itemID: itemID} });}})module.exports = listdata

Last, use an index file to merge these two api into one

const datasources = () => {   return {       userAPI: UserAPI,       listAPI: ListAPI,   }};module.exports = datasources;

Schema and Resolver

Now that we have functions to merge APIs, another important feature of GraphQL is to query exact what you need, and this is handled using Schema and Resolver. Schema is to define the data while resolver is responsible to populate it.

//Schema
const { gql } = require('apollo-server');
const baseSchema = gql` type Query {_: Boolean} type Mutation {_: Boolean} type User { userID: String! userName: String! }`module.exports = baseSchema;//Resolver
const userResolvers = {
Query: {user: (id) => {}}};module.exports = userResolvers;

GraphQL server

First we need to install the Apollo server:

npm install apollo-server graphql 

Now let’s create a GraphQL server file — project/src/app.js.

const { ApolloServer } = require('apollo-server');
const typeDefs = require('./schema');
const resolvers = require('./resolvers');
const datasources = require('./datasources');
const server = new ApolloServer({typeDefs,resolvers,dataSources});server.listen({port: 8080}, () => {
console.log('Server is running');
});

Kick-off start

npm install
npm start

Target architecture

Shall you use GraphQL to replace REST? Probably not. It is better to use GraphQL as an extra layer in front of REST API services. In this way, the backend team can focus on building the core services, while frontend team can optimise the server response in such way that works best for its performance.

Flutter GraphQL Client

The transition mobile app layer contains: presentation, domain and data, and usually the data layer is responsible for fetching, mapping and storing data. Is there a better way? What if we can ditch the data layer? With GraphQL it is possible.

Using GraphQL in Flutter is fairly easy, unfortunately at the time of writing this article, there isn’t a Apollo Flutter lib, therefore we will be using the GraphQL lib only. Let’s see the dependencies:

name: graph_ql...dependencies:    graphql_flutter: ^4.0.0-beta

Init and create GraphQL server in main()

void main() => runApp(MyApp());class MyApp extends StatelessWidget {  @override  Widget build(BuildContext context) {     ValueNotifier<GraphQLClient> client =    ValueNotifier(GraphQLClient(link:HttpLink('http://localhost:8080/graphql')));

return GraphQLProvider(
client: client,
child: MaterialApp(home: UserScreen()));
}
}

Create a GraphQL scheme

final String getItem = """query {   item(id: "1") {user(id: "2") {name}}}""";

Ues the data inside a Widget

class ItemScreen extends StatelessWidget {  @override  Widget build(BuildContext context) {    return Scaffold(       body: Container(          child: Query(             options: WatchQueryOptions(document: gql(getItem), fetchPolicy: FetchPolicy.networkOnly),             builder: (QueryResult result, {VoidCallback refetch,    FetchMore fetchMore}) {               if (result.data == null) return Text('Error')               if (result.isLoading) return Text('Loading');               return _buildUserWidget(result.data);               })));  }}

🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉

Enthusiastic about cloud technology, data, clean code, Flutter, and Agile