Android GraphQL API Integration with Apito
Learn how to integrate Apito’s GraphQL tools and database API with your Android applications using Apollo Android. This instant API builder provides powerful GraphQL endpoints and build API tool features optimized for mobile development.
Overview
Apito’s GraphQL tools and database API offer seamless integration with Android applications through Apollo Android client. This instant API platform generates type-safe Kotlin/Java models from your GraphQL schema, ensuring excellent performance and developer experience on mobile devices.
Prerequisites
- Android Studio Arctic Fox or later
- Kotlin 1.5+ or Java 8+
- Minimum SDK 21 (Android 5.0)
- An Apito project with GraphQL API enabled
Installation
Add Apollo Android Dependencies
Add the following dependencies to your app-level build.gradle file:
dependencies {
implementation 'com.apollographql.apollo3:apollo-runtime:3.8.2'
implementation 'com.apollographql.apollo3:apollo-android-support:3.8.2'
// For coroutines support
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
}
Apply Apollo Plugin
Add the Apollo plugin to your app-level build.gradle:
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'com.apollographql.apollo3' version '3.8.2'
}
Configuration
Download GraphQL Schema
- Navigate to your Apito Console
- Go to API Explorer section
- Click on GraphQL tab
- Download the schema file as
schema.graphqls - Place it in
src/main/graphql/directory
Configure Apollo
Create an apollo configuration block in your build.gradle:
apollo {
service("apito") {
packageName.set("com.yourapp.graphql")
schemaFile.set(file("src/main/graphql/schema.graphqls"))
}
}
Implementation
Initialize Apollo Client
Create an Apollo client in your Application class or dependency injection module:
import com.apollographql.apollo3.ApolloClient
import com.apollographql.apollo3.network.okHttpClient
import okhttp3.Interceptor
import okhttp3.OkHttpClient
class ApitoGraphQLClient {
companion object {
private const val BASE_URL = "https://api.apito.io/secured/graphql"
private const val API_KEY = "your-api-key-here"
val apolloClient: ApolloClient by lazy {
val okHttpClient = OkHttpClient.Builder()
.addInterceptor { chain ->
val request = chain.request().newBuilder()
.addHeader("X-API-KEY", API_KEY)
.addHeader("Content-Type", "application/json")
.build()
chain.proceed(request)
}
.build()
ApolloClient.Builder()
.serverUrl(BASE_URL)
.okHttpClient(okHttpClient)
.build()
}
}
}
Create GraphQL Queries
Create GraphQL query files in src/main/graphql/:
GetProducts.graphql:
query GetProducts($limit: Int, $offset: Int) {
products(limit: $limit, offset: $offset) {
id
title
description
price
image {
url
}
categories {
id
name
}
}
}
CreateProduct.graphql:
mutation CreateProduct($input: ProductInput!) {
createProduct(input: $input) {
id
title
description
price
createdAt
}
}
Usage in Activities/Fragments
Fetching Data with Coroutines
import com.apollographql.apollo3.exception.ApolloException
import kotlinx.coroutines.launch
import androidx.lifecycle.lifecycleScope
class ProductActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_product)
fetchProducts()
}
private fun fetchProducts() {
lifecycleScope.launch {
try {
val response = ApitoGraphQLClient.apolloClient
.query(GetProductsQuery(limit = 10, offset = 0))
.execute()
if (response.hasErrors()) {
// Handle GraphQL errors
response.errors?.forEach { error ->
Log.e("GraphQL", "Error: ${error.message}")
}
} else {
// Handle successful response
response.data?.products?.let { products ->
displayProducts(products)
}
}
} catch (e: ApolloException) {
Log.e("Apollo", "Network error: ${e.message}")
}
}
}
private fun displayProducts(products: List<GetProductsQuery.Product>) {
products.forEach { product ->
Log.d("Product", "Title: ${product.title}, Price: ${product.price}")
}
// Update your RecyclerView or UI components
}
}
Creating Data with Mutations
private fun createProduct(title: String, description: String, price: Double) {
lifecycleScope.launch {
try {
val input = ProductInput(
title = title,
description = description,
price = price
)
val response = ApitoGraphQLClient.apolloClient
.mutation(CreateProductMutation(input))
.execute()
if (response.hasErrors()) {
// Handle errors
showError("Failed to create product")
} else {
// Handle success
response.data?.createProduct?.let { product ->
showSuccess("Product created with ID: ${product.id}")
}
}
} catch (e: ApolloException) {
showError("Network error: ${e.message}")
}
}
}
Repository Pattern Implementation
For better architecture, implement the Repository pattern:
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ProductRepository @Inject constructor(
private val apolloClient: ApolloClient
) {
suspend fun getProducts(limit: Int, offset: Int): Result<List<Product>> {
return try {
val response = apolloClient
.query(GetProductsQuery(limit, offset))
.execute()
if (response.hasErrors()) {
Result.failure(Exception("GraphQL errors: ${response.errors}"))
} else {
val products = response.data?.products?.map { it.toProduct() } ?: emptyList()
Result.success(products)
}
} catch (e: ApolloException) {
Result.failure(e)
}
}
suspend fun createProduct(productInput: ProductInput): Result<Product> {
return try {
val response = apolloClient
.mutation(CreateProductMutation(productInput))
.execute()
if (response.hasErrors()) {
Result.failure(Exception("GraphQL errors: ${response.errors}"))
} else {
response.data?.createProduct?.let { product ->
Result.success(product.toProduct())
} ?: Result.failure(Exception("No data received"))
}
} catch (e: ApolloException) {
Result.failure(e)
}
}
}
// Extension function to map GraphQL types to domain models
private fun GetProductsQuery.Product.toProduct(): Product {
return Product(
id = id,
title = title,
description = description,
price = price,
imageUrl = image?.url
)
}
ViewModel Integration
Use with Android Architecture Components:
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class ProductViewModel @Inject constructor(
private val productRepository: ProductRepository
) : ViewModel() {
private val _products = MutableStateFlow<List<Product>>(emptyList())
val products: StateFlow<List<Product>> = _products
private val _loading = MutableStateFlow(false)
val loading: StateFlow<Boolean> = _loading
private val _error = MutableStateFlow<String?>(null)
val error: StateFlow<String?> = _error
fun loadProducts() {
viewModelScope.launch {
_loading.value = true
_error.value = null
productRepository.getProducts(limit = 20, offset = 0)
.onSuccess { products ->
_products.value = products
}
.onFailure { exception ->
_error.value = exception.message
}
_loading.value = false
}
}
fun createProduct(title: String, description: String, price: Double) {
viewModelScope.launch {
val input = ProductInput(title, description, price)
productRepository.createProduct(input)
.onSuccess {
loadProducts() // Refresh the list
}
.onFailure { exception ->
_error.value = exception.message
}
}
}
}
Error Handling
Implement comprehensive error handling:
sealed class GraphQLResult<T> {
data class Success<T>(val data: T) : GraphQLResult<T>()
data class Error<T>(val message: String, val errors: List<com.apollographql.apollo3.api.Error>? = null) : GraphQLResult<T>()
data class NetworkError<T>(val exception: ApolloException) : GraphQLResult<T>()
}
suspend fun <T> executeGraphQLQuery(
query: suspend () -> com.apollographql.apollo3.api.ApolloResponse<T>
): GraphQLResult<T> {
return try {
val response = query()
if (response.hasErrors()) {
GraphQLResult.Error(
message = "GraphQL errors occurred",
errors = response.errors
)
} else {
response.data?.let { data ->
GraphQLResult.Success(data)
} ?: GraphQLResult.Error("No data received")
}
} catch (e: ApolloException) {
GraphQLResult.NetworkError(e)
}
}
Best Practices
1. Caching Strategy
// Enable normalized caching
val apolloClient = ApolloClient.Builder()
.serverUrl(BASE_URL)
.normalizedCache(
MemoryCacheFactory(maxSizeBytes = 10 * 1024 * 1024) // 10MB
)
.build()
2. Network Optimization
- Use appropriate cache policies
- Implement proper retry mechanisms
- Handle offline scenarios gracefully
3. Security
- Store API keys securely using Android Keystore
- Implement certificate pinning for production
- Validate all user inputs before mutations
Conclusion
Integrating Apito’s GraphQL API with Android applications provides a robust, type-safe solution for mobile data management. This open source API builder offers excellent performance and developer experience for Android development.
The combination of Apito’s open source CMS and Apollo Android ensures scalable, maintainable mobile applications with powerful GraphQL integration.
Next Steps
- Explore Apito Console for GraphQL schema management
- Learn about Authentication for secure API access
- Check out other Mobile Integrations for cross-platform development