Using GraphQL API in Android

Using GraphQL API in Android

AndroidKotlin
Fix bugs faster! Log Collection Made Easy
START NOW!

Since it was created by Facebook in 2012 and made publicly available in 2015, GarphQL has changed everything about how we fetch data from servers for our front-end apps. Most front-end clients typically use REST APIs to retrieve data from the server, this includes mobile apps for platforms like Android, iOS, and Flutter, as well as JavaScript frameworks like React, Angular, Vue, and Next.

A huge advantage of GraphQL is that it enables front-end clients to request only the API they require. Front-end clients use the GraphQL query language to specify the data they need from an API, then a GraphQL server processes these queries over HTTP returning only the data requested by the client.

In this tutorial, we we’re going to consider some of the key features and benefits offered by GraphQL before demonstrating by building two example projects – first we’ll create a Node.js app which will give us a GraphQL server/endpoint, then we’ll build an Android app that consumes that endpoint.

Features and benefits of GraphQL

Let’s start by taking a look at some of the key features and benefits of GraphQL:

Efficient data fetching

Unlike REST APIs (where multiple endpoints may need to be called to fetch related data), GraphQL allows clients to request only the specific data they need in a single query, reducing over-fetching and under-fetching of data.

Declarative data fetching

GraphQL clients can specify the shape and structure of the data they need using a declarative query language. This empowers clients to define their data requirements without having to make changes on the server side.

Strongly typed schema

A strongly typed schema, which serves as a contract between the client and server, is what powers GraphQL APIs, defining the types of data available and the operations that can be performed to provide clarity and validation during development.

Real-time updates

GraphQL supports real-time data updates through subscriptions, meaning clients can subscribe to specific data events and receive updates from the server when relevant data changes, enabling features like live notifications and chat.

Versioning and evolution

With GraphQL, as clients can specify exactly the fields they require, there’s no need for versioning endpoints. This allows for seamless evolution of APIs without breaking changes, as new fields can be added to the schema without impacting existing clients.

Batching and caching

GraphQL queries can be batched together, reducing the number of HTTP requests and improving network efficiency. Additionally, GraphQL responses can be cached at various levels (e.g. client, server, and CDN) for further optimization.

Tooling and ecosystem

GraphQL has a rich ecosystem of tools and libraries for various platforms and languages, including client frameworks, server implementations, IDE plugins, and developer tools. These tools enhance developer productivity and provide support for features like linting, code generation and debugging.

Cross-platform compatibility

As it’s transport agnostic GraphQL can be used with any programming language or platform and can be integrated over HTTP, WebSockets, or any other network protocol. This flexibility makes it ideal for building APIs for web, mobile, IoT, and other platforms.

Developer experience

GraphQL provides a more intuitive and developer-friendly experience compared to traditional REST APIs. Its self-documenting nature, interactive tooling (like GraphiQL), and introspection capabilities make it easier to explore and understand the API schema.

Fantastic. Now we’ve covered the key features and benefits we can get started on our demo projects.

Using Node.js to Create a GraphQL API

Let’s begin our tutorial by creating the GraphQL API using the Node.js framework and Express library. This combination will allow us to build a quick server to later construct our Android GraphQL app, which will consume this API.

To create a GraphQL server in Node.js with Express, we will need to follow these steps:

Setup project:

Firstly, if you haven’t installed Node.js go ahead and install it.

Now we’ll need to create a new directory for our project and initialize a Node.js project using npm or yarn, like this:

mkdir graphql-server

cd graphql-server

npm init -y

Install dependencies and configure Nodemon:

Next we can install the necessary dependencies, including Express, Express-GraphQL for handling GraphQL requests, and GraphQL for creating the schema, as below:

npm install express express-graphql graphql --save

We’ll also require the nodemon, as follows:

npm install --save-dev nodemon

Now we can update our package.json and add nodemon so we can run the server by npm run dev, like this:

"scripts": {
	"dev": "nodemon server.js"
},

Finally, our package.json looks like the below:

{
    "name": "bug",
        "version": "1.0.0",
            "description": "",
                "main": "server.js",
                    "scripts": {
        "dev": "nodemon server.js"
    },
    "author": "",
        "license": "ISC",
            "dependencies": {
        "express": "^4.18.2",
            "express-graphql": "^0.12.0",
                "graphql": "^15.8.0"
    },
    "devDependencies": {
        "nodemon": "^3.0.1"
    }
}

Make an app with Express

For this example our data can be hardcoded for simplicity, although in the real world we’d probably need to query the data from a database.

It’s also worth remembering that the GraphQL API created through this tutorial only has a method to query all items at once, where more advanced projects will have multiple methods.

The following code shows how to create the Node.js app:

const express = require('express')
const expressGraphQL = require('express-graphql').graphqlHTTP
const {
    GraphQLSchema,
    GraphQLObjectType,
    GraphQLString,
    GraphQLList,
    GraphQLInt,
    GraphQLNonNull
} = require('graphql')

const app = express()
const movies = [
    { id: 1, name: 'Matrix', thumb: "<https://upload.wikimedia.org/wikipedia/en/thumb/c/c1/The_Matrix_Poster.jpg/220px-The_Matrix_Poster.jpg>" },
    { id: 2, name: 'Jason Bourne', thumb: "<https://upload.wikimedia.org/wikipedia/en/b/b2/Jason_Bourne_%28film%29.jpg>" },
    { id: 3, name: 'Interstellar', thumb: "<https://upload.wikimedia.org/wikipedia/en/b/bc/Interstellar_film_poster.jpg>" },
    { id: 4, name: 'The International', thumb: "<https://upload.wikimedia.org/wikipedia/en/thumb/4/4c/The_International_poster.jpg/220px-The_International_poster.jpg>" },
    { id: 5, name: 'Star Trek Into Darkness', thumb: "<https://upload.wikimedia.org/wikipedia/en/thumb/5/50/StarTrekIntoDarkness_FinalUSPoster.jpg/220px-StarTrekIntoDarkness_FinalUSPoster.jpg>" },
]

const MovieType = new GraphQLObjectType({
    name: 'Movie',
    description: 'This represents a movie',
    fields: () => ({
        id: { type: GraphQLNonNull(GraphQLInt) },
        name: { type: GraphQLNonNull(GraphQLString) },
        thumb: { type: GraphQLNonNull(GraphQLString) },
    })
})

const RootQueryType = new GraphQLObjectType({
    name: 'Query',
    description: 'Root Query',
    fields: () => ({
        movies: {
            type: new GraphQLList(MovieType),
            description: 'List of All Movies',
            resolve: () => movies
        },
    })
})

const schema = new GraphQLSchema({
    query: RootQueryType
})

app.use('/movie', expressGraphQL({
    schema: schema,
    graphiql: true
}))

app.listen(5000, () => console.log('Server Running'))

Great stuff! Now let’s test it.

Test in a browser

Launch a web browser and navigate to http://localhost:5000/movie to access the GraphQL interface, you can see GraphQL queries, and results are available now.

Here’s an example query in the GraphiQL query schema:

{
  
  movies{
    id,
    name,
    thumb
  }
}

And the response should look like this:

{
  "data": {
    "movies": [
      {
        "id": 1,
        "name": "Matrix",
        "thumb": "<https://upload.wikimedia.org/wikipedia/en/thumb/c/c1/The_Matrix_Poster.jpg/220px-The_Matrix_Poster.jpg>"
      },
      {
        "id": 2,
        "name": "Jason Bourne",
        "thumb": "<https://upload.wikimedia.org/wikipedia/en/b/b2/Jason_Bourne_%28film%29.jpg>"
      },
      {
        "id": 3,
        "name": "Interstellar",
        "thumb": "<https://upload.wikimedia.org/wikipedia/en/b/bc/Interstellar_film_poster.jpg>"
      },
      {
        "id": 4,
        "name": "The International",
        "thumb": "<https://upload.wikimedia.org/wikipedia/en/thumb/4/4c/The_International_poster.jpg/220px-The_International_poster.jpg>"
      },
      {
        "id": 5,
        "name": "Star Trek Into Darkness",
        "thumb": "<https://upload.wikimedia.org/wikipedia/en/thumb/5/50/StarTrekIntoDarkness_FinalUSPoster.jpg/220px-StarTrekIntoDarkness_FinalUSPoster.jpg>"
      }
    ]
  }
}

That’s it!

Using Node.js and Express we have successfully built a simple GraphQL server. This is the starting point for extending our GraphQL schema with additional types, mutations, database or external API integrations.

If you’re looking for more advanced information, make sure to read the Express-GraphQL and GraphQL official documentation.

Now let’s look at building an Android app to utilize our GraphQL server.

Building an Android app using the Apollo Kotlin client

Android doesn’t have any official libraries for GraphQL so we’re going to use the Apollo Android Kotlin library for our project, which is a simple native Android project using the Kotlin language.

When we’re finished, our app will look like this:

Project setup

Let’s start by opening Android Studio and creating a new project called FavoriteMovie using Kotlin as the language and Jetpack for building the native UI.

Next, we can configure and install the Apollo Kotlin libraries as shown below:

Before moving on to the next section, we need to add permission to our AndroidManifest.xml to access the internet and network security configurations to access our GraphQL API, which uses the HTTP protocol, like this:

Now we’ll create a new XML file called network_security_config in res/xml/ directory in our Android project, declaring that we want to use IP 10.0.2.2 with HTTP as below:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">10.0.2.2</domain>
    </domain-config>
</network-security-config>

It’s important to remember that this is the IP the Android emulator uses to access our http://localhost:5000 endpoint so we’ll need to specify this IP in our network security configuration file for proper access.

Our Node.js is accessible from our computer’s browser using localhost, but we must use 10.0.2.2 from the Android emulator.

Apollo Kotlin Installation

We’re now ready to start installing the Apollo Kotlin library to access our GraphQL APIs.

To apply the plugin, open the app/build.gradle.kts (one that has a dependencies { } block) file and add the following lines at the beginning:

plugins {
    alias(libs.plugins.androidApplication)
    alias(libs.plugins.jetbrainsKotlinAndroid)
    
    // Apollo GraphQL
    id("com.apollographql.apollo3") version "4.0.0-beta.5"
}

// Apollo GraphQL
apollo {
    service("movie-service") {
        packageName.set("com.bugfender.movieserver")
    }
}

Now we’re ready to add our Apollo Kotlin library to our project and start using it to interact with our GraphQL API.

Scroll to the bottom, and under the dependencies block, add this:

implementation("com.apollographql.apollo3:apollo-runtime:4.0.0-beta.5")

We will need another library called Coil to cache our movie’s image. Add Coil to our implementation section as well, like this:

implementation("io.coil-kt:coil-compose:2.6.0")

Sync the build file now.

Next, in order for Apollo Kotlin to produce type-safe models and code based on our queries, we’ll create a GraphQL schema. We can create a schema in a variety of ways but in this tutorial we’re using the downloadApolloSchema Gradle task that our plugin automatically created for us.

From the root of the project, run the following in Android Studio’s Terminal tab:

./gradlew :app:downloadApolloSchema --endpoint='<http://localhost:5000/movie>' --schema=app/src/main/graphql/schema.graphqls

If everything goes fine, we will see a BUILD SUCCESSFUL result, like this:

In the above command, we use the downloadApolloScheme tool and specify the endpoint of our GraphQL server and the location of the schema file to be saved.

This will download a schema.graphqls file from our endpoint to app/src/main/graphql/schema.graphqls file, as shown below:

Excellent work! Now let’s look at the final few steps to get our app up and running.

Add the query to our project

Right click on the src/main/graphql/ folder and create a new file named MovieList.graphql, this folder should contain our schema.graphqlsand it’s crucial to make sure it’s saved at the same level as our schema.graphqls file.

Next we need to copy our final query from GraphQL Explorer (http://localhost:5000/movie) and paste it into MovieList.graphql, like this:

query MovieList {
  movies{
    id,
    name,
    thumb
  }
}

Generate the model

When we build our project, the Apollo Kotlin tool will make our first model. To make the models the tool sets up a task called generateApolloSources – it’s not necessary to run this as It will run automatically when we build our project.

It’s also worth remembering that autocomplete won’t work until we build our project.

Create an ApolloClient

Next we’ll create a new file called GraphQLClient and add the following code:

package com.bugfender.android.favoritemovie

import com.apollographql.apollo3.ApolloClient

val GraphQLClient = ApolloClient.Builder()
    .serverUrl("<http://10.0.2.2:5000/movie>")
    .build()

This will use ApolloClient to make the network request to our GraphQL server.

Now, we have the option to either use Jetpack Compose or stick with the traditional Android method of app development. Since Jetpack Compose is the most up-to-date and effective method for creating native Android apps, we decided to use it for our demo.

In Jetpack Compose, we can use ViewModel to make the business logic or maintain the UI state level.

Next we’ll create a new file called MovieViewModel, which we’ll use to call the GraphQLClient to get the data from the GraphQL server – we’ll call the function getMovieList() from the UI.

This function gets data from the GraphQL client and adds all the movies to our movieList variable, as you can see below:

package com.bugfender.android.favoritemovie.viewmodel

import androidx.compose.runtime.mutableStateListOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.bugfender.android.favoritemovie.GraphQLClient
import com.bugfender.movieserver.MovieListQuery
import kotlinx.coroutines.launch

class MovieViewModel : ViewModel() {
    private val _movieList = mutableStateListOf<MovieListQuery.Movie>()
    val movieList: List<MovieListQuery.Movie> = _movieList

    fun getMovieList() {
        viewModelScope.launch {
            val response = GraphQLClient.query(MovieListQuery()).execute()
            val tempList = response.data?.movies as List<MovieListQuery.Movie>
            for (movie in tempList) {
                _movieList.add(movie)
            }
        }
    }
}

Now we’ll open MainActivity.kt and build a simple UI that has a list of movies; each movie item has a name and image.

At the beginning of the function MovieView, we use LaunchedEffect to call our ViewModel in the background, which doesn’t block the UI, LaunchedEffect is the easiest way to handle asynchronous tasks.

As soon as the data arrives, we loop through the movie item and generate the list item, We also use AsyncImage from the Coil library to cache the image.


fun MovieView(vm: MovieViewModel) {
    LaunchedEffect(Unit, block = {
        vm.getMovieList()
    })

    Scaffold(
        topBar = {
            TopAppBar(
                title = {
                    Text(text = "Favorite Movie")
                }, colors = TopAppBarDefaults.topAppBarColors(
                    titleContentColor = Color.Black,
                    containerColor = Color.LightGray
                )
            )
        },
        content = { paddingValues ->
            Box(modifier = Modifier
                .fillMaxSize()
                .padding(paddingValues)) {
                LazyColumn {
                    items(vm.movieList) { item ->
                        Row(
                            Modifier.padding(8.dp),
                            verticalAlignment = Alignment.CenterVertically
                        ) {
                            AsyncImage(
                                model = item.thumb,
                                contentDescription = null
                            )
                            Spacer(modifier = Modifier.size(10.0.dp))
                            Text(text = item.name, fontWeight = FontWeight.Bold, fontSize = 14.0.sp)
                        }
                    }
                }    
            }
            
        },
    )
}

Finally, we can now run the app on Android Studio and see our FavoriteMovie app, which shows all our favorite movies from the GraphQL server.

To sum up

In this article we looked at how GraphQL APIs can simplify Android app client-server communication, starting with a simple Node.js and Express project to set up a GraphQL server, define a schema, and resolve queries that met our client’s demands.

In the second half, we built an Android app that uses GraphQL, using Jetpack and the Apollo Kotlin library to smoothly retrieve and show data in GraphQL way.

GraphQL is ideal for modern app development due to its single endpoint architecture, ability to query precisely what is needed, real-time data changes, introspection, and batching and caching.

Expect the Unexpected! Debug Faster with Bugfender
START FOR FREE

Trusted By

/assets/images/svg/customers/projects/sk_telecom.svg/assets/images/svg/customers/projects/slack.svg/assets/images/svg/customers/cool/levis.svg/assets/images/svg/customers/highprofile/intel.svg/assets/images/svg/customers/cool/riachuelo.svg/assets/images/svg/customers/highprofile/oracle.svg/assets/images/svg/customers/highprofile/adt.svg/assets/images/svg/customers/highprofile/rakuten.svg

Already Trusted by Thousands

Bugfender is the best remote logger for mobile and web apps.

Get Started for Free, No Credit Card Required