A full-fledged guide about GraphQL for Android
GraphQL information
In the previous blog, we configured the project structure and added an empty schema.sdl
file. In this part, we will see how to write Query and Mutation and the necessary steps to employ them.
Let’s get the schema
There are two ways, one is manually from the playground, and another is using the config file provided by JS graphQL plugin.
1. Manually from the playground
First, open GraphQL Playground here is the link:
https://www.graphqlbin.com/v2/new
Paste Rick and Morty API link in the GraphQL Playground:
https://rickandmortyapi.com/graphql
When the playground is open, you will see on the right side two tabs: DOCS and SCHEMA.
Click on SCHEMA, and copy-paste the code into schema.json
2. Using graphQL config file
In the folder where you have kept the schema file and Query files, add the config file as below with your URL and agent that you use.
It’s a part of the JS graphQL plugin, which enables you to make queries and mutation requests.
{
“name”: “Untitled GraphQL Schema”,
“schemaPath”: “schema.sdl”,
“extensions”: {
“endpoints”: {
“Default GraphQL Endpoint”: {
“url”: “https://rickandmortyapi.com/graphql",
“headers”: {
“user-agent”: “JS GraphQL”
},
“introspect”: false
}
}
}
}
Now to download schema from the back end, run the following command from the android terminal.
./gradlew downloadApolloSchema \
--endpoint=”https://rickandmortyapi.com/graphql" \
--schema=”app/src/main/graphql/com/example/schema.graphqls”
You can check Query in Playground (aka GraphiQl)
query CharactersData {
characters {
results {
id
name
episode{
name
episode
}
}
}
}
The query name is CharactersData
for Apollo to generate a Kotlin file. We have to give the query a name.
The next lines are called fields which describe what we want to query.
Let’s Create a Query file
Create a new file in the same package like your schema.sdl
Create the query file, E.g. CharactersData.graphql
Copy the query that you tested in the left panel of the playground and paste it in your CharactersList.graphql
file.
Now sit back and Rebuild the Project
Apollo client will create a Kotlin file of the CharactersData.graphql
file. The client will automatically generate a model class based on your query file.
Search for CharactersDataQuery
.Here .kt file will be auto-generated with Query postfix.
Open the file CharactersDataQuery
.You can search it in Android Studio by using Ctrl + Shift + F
.
There you will find a Result data class with fields we need for our list query.
data class Result(
val __typename: String = "Character",
val id: String?,
val name: String?,
val status: String?,
val species: String?,
val gender: String?,
val origin: Origin?
)
Building an Apollo client
Now we need an instance of ApolloClient. Before implementing the CharactersRepositoryImpl let us implement the class for the ApolloClient. Create a new package and name it a network. Create there a class CharApiService.
As you can see this class creates the ApolloClient and does the network call to the Rick and Morty API endpoint.
The builder offers a collection of ways to configure the client:
- serverUrl(): This is used to define the URL of the API that is going to be communicated with
- okHttpClient(): Provide an okHttp client reference to be used when making requests
- logger(): Provide an instance of a com.apollo.graphql.logger to be used for logging
- addApplicationInterceptor(): Add an ApolloInterceptor that can be used to observe the entire lifecycle of a request
- defaultCacheHeaders(): Provide a key/value pair collection of cache headers in the form of an apollo CacheHeaders reference
- defaultHttpCachePolicy(): Declare the cache policy to be used for GraphQl operations other than mutations
- httpCache(): Provide configuration (in the form of an Apollo HttpCache reference) to be used for the request + response cache
- dispatcher(): Provide an Executor reference to be used when dispatching requests
- addCustomTypeAdapter(): Add an adapter used for serializing and deserializing custom GraphQl scalars
Executing an Operation
With our Apollo Client in place, we’re ready to execute our generated query CharactersDataQuery
. For this we’re going to utilize the query function of the ApolloClient — this takes a reference to a generated Query class and returns us a reference to an ApolloQueryCall class.
Await is a suspending function that gives us a Result object that represents the response of our request. And the result will be returned as a suspending function.
With this in place, we have a starting point for executing query requests against our GraphQL schema!
Sample image that exemplifies how you can make use of query response.
Now let’s start with Mutation
So far we have covered graphQL and Query, we saw how to access or read data using queries, now let’s see how to change or “mutate” information using mutations!
What is Mutation
In GraphQL, there are only two types of operations you can perform: queries and mutations.
The mutation is a way to modify server-side data. If queries in the GraphQL are equivalent to GET calls in REST, then mutations represent the state-changing methods in REST (like DELETE, PUT, PATCH, etc)
In simple words, we use queries to fetch data, and mutations to modify server-side data.
Simple Mutation examples
Suppose we have a pet shop GraphQL API. Here, the query to fetch all the pets from the app might look like this:
query GetAllPets {
pets {
name
petType
}
}
Now suppose we want to add a new puppy or remove one from the Server. Mutation shines for such use cases :
mutation AddNewPet ($name: String!, $petType: PetType) {
addPet(name: $name, petType: $petType) {
id
name
petType
}
}
Here, the AddNewPet
mutation expects values for the name
and petType
variables, these Input variable allows us to pass data that we want to be added to our table, inside the curly bracket we can define what response we want after adding a post.
The request data for this mutation holds the following shape:
{
“name”: “Rover”,
“petType”: “DOG”
}
In the mutation response, you could expect to see the following result.
{
“data”: {
“addPet”: {
“id”: 1
“name”: “Rover”,
“petType”: “DOG”
}
}
}
Structure of Mutation
The structure of Mutations looks very similar to queries. If you’ll recall, the general structure of a GraphQL operation looks like this.
One difference you will see is that the Operation type for the mutation will be mutation
. We use the word “query” for queries and “mutation” for mutations.
Another important thing to note is that we signal the mutation we want to invoke by naming it exactly as it occurs within our server-side GraphQL API.
In the AddNewPet example, the name of the mutation is addPet
, which should be the same as described in the schema.
Does your API support Mutation?
It’s crucial to understand the structure of schema before going further with mutation.
As we have discussed before, Schema describes the capabilities of your Server. First, check if your API supports Mutation. For that, go to your Schema.sdl
file and search for Type mutation.
type Mutation {
bookTrips(launchIds: [ID]!): TripUpdateResponse!
cancelTrip(launchId: ID!): TripUpdateResponse!
login(email: String): String
uploadProfileImage(file: Upload!): User
}
If you find type mutation in your downloaded schema file, then you are good to follow the following steps where I will show you how to implement mutation.
Start by including essential parts to start with a mutation
Adding dependencies and schema files is the same as I have already discussed in the Query section. You can check API by yourself in graphiQL,
open GraphQL Playground here is the link:https://www.graphqlbin.com/v2/new
Paste in the GraphQL Playground the Heroku API link: https://apollo-fullstack-tutorial.herokuapp.com/graphql
User authentication with Mutation
Firstly authentication is required, which will enable you to book and cancel trips in your app. Add Login mutation as below.
As we have discussed in the simple example section, the name of the mutation login
should be the same as described in Schema.sdl
.
type Mutation {
bookTrips(launchIds: [ID]!): TripUpdateResponse!
cancelTrip(launchId: ID!): TripUpdateResponse!
login(email: String): User
uploadProfileImage(file: Upload!): User
}
In the playground put the mutation, and add an email in the query section.
{ “email”: “me@example.com” }
Press the Play button, and see the response:
The response we are getting is a token that we will need while booking and canceling the trip.
Now go to Build -> Rebuild Project. Build your project to generate the UserLoginMutation
class.
Let’s implement Apollo Client
Since Apollo Android is using OkHttp to handle HTTP requests, you will use OkHttp Interceptors to add headers to your GraphQL requests. Let’s create a Service and Interceptor class.
This interceptor appends an “Authorization: $token” HTTP header to every request.
Executing an Operation
With our Apollo Client in place, we’re ready to execute our generated mutation UserLogin
. For this we’re going to utilize the mutate
function of the ApolloClient — this takes a reference to a generated Mutation class.
Await is a suspending function that gives us a Result object that represents the response of our request as I have mentioned before in the Query section.
By creating an appropriate UI for taking user credentials you can make use of the Login Mutation for authentication. After successful authentication, you will receive a token in response which you will need for booking or canceling the trip. Check the implementation of Apollo client wherein the Interceptor we are passing this token as a Header.
Let’s book a flight 🚀 with Mutation
Now First, let’s check the booking and cancellation process in the Playground.
Booking process in the playground
see here how to pass the token to the header. In the query variable, you will have to pass id
which you can see in the canceling process down below.
Canceling process in the playground
Let’s talk about the Trip, shall we?
Now that the user authentication part is completed, let’s book a flight. Add the BookTrip and CancelTrip mutations. In the same folder where you have kept Schema.sdl
file, create files BookTrip.graphql
and CancelTrip.graphql
. Also, add Query to track the total number of booked Trips. dd TotalBookedTrips.graphql
file.
Notice how the BookTrip
the field takes a list as an argument but the mutation itself only takes a single variable. The CancelTrip
mutation doesn’t use a list.
Here is a glimpse of how you can employ mutations to book or cancel the trip, and also with the query you can check the total booked trip.
This is a sample gif that exhibits how mutation would work for user authentication, booking, or canceling a trip and to substantiate the functionality of mutation using Query TotalBookedTripsQuery
.
Okay, so that’s it for this part. If you have enjoyed this article give it a clap.