





















































MobilePro #194: Behind Every Connected App—The Power of REST and APIs
Hi ,
Welcome to the 194th edition of MobilePro!
Every app needs data — but not all data is created equal. Some can live quietly inside your codebase, but the moment you need live updates, dynamic content, or anything that changes in real time, you have to reach beyond the app and talk to the web. That’s where REST and APIs step in.
In this issue of MobilePro, we’re breaking down the backbone of modern app communication — RESTful APIs — and the formats that make them tick: JSON and XML. You’ll learn how these technologies let your app fetch, send, and process live data seamlessly, without constant code updates or manual refreshes.
We’ll cover:
Whether you’re new to backend interaction or just want a clearer picture of how data actually moves between your app and the web, this guide will get you there — fast.
This is excerpted from the bookHow to Build Android Applications with Kotlin, written by Alex Forrester, Eran Boudjnah, Alexandru Dumbravan, and Jomar Tigcal.
Before we jump in though, let's take a quick look at last week's highlights:
Join Snyk October 22, 2025 for this one-day event to hear from leading AI and security experts from Qodo, Ragie.ai, Casco, Arcade.dev, and more!
The agenda includes inspiring Mainstage keynotes, a hands-on AI Demos track on building secure AI, Snyk's very FIRST AI Developer Challenge and more!
Senior Android Developer
NatWest Group
Director
Mitteloupe Limited
Principal Android Engineer
Nutmeg
Lecturer
De La Salle University
Data shown to users can be hardcoded (static) or fetched dynamically. Hardcoded data limits flexibility since updates require republishing the app. Dynamic or time-sensitive data, like exchange rates, weather, or asset availability, must be fetched from a server.
A common architecture for serving such data is Representational State Transfer (REST).
The REST architecture isdefined by a set of six constraints: client-server architecture, statelessness, cacheability, a layered system, code on demand (optional), and a uniform interface.
When applied to a web service application programming interface (API), we get a Hypertext Transfer Protocol (HTTP)-based RESTful API. The HTTP protocol is thefoundation of data communication for the World Wide Web, hosted on and accessible via the internet. It is the protocol used by servers all around the world to serve websites to users in the form of HTML documents, images, style sheets, and so forth.
RESTful APIs rely on the standard HTTP methods—GET, POST, PUT, DELETE, and PATCH—to fetch and transform data. These methods allow us to fetch, store, delete, and update data entities on remote servers.
The Android platform includes an HttpURLConnection client to execute these HTTP methods. However, it has limited capabilities, so in modern Android projects, we commonly rely on third-party libraries instead. Common libraries for this purpose are Retrofit and Ktor. In this chapter, we will use Ktor. Ktor is an HTTP client and server library that was developed by JetBrains using Kotlin. We will use it to fetch data from web APIs.
Most commonly, such data is represented by JSON.
JSON is a text-based data transfer format. As the name implies, it was derived from JavaScript. In fact, a JSON string can be used as-is as a valid data structure in JavaScript. JSON has become one of the most popular standards for data transfer, and its most modern programming languages have libraries that encode or decode data to or from JSON.
A simple JSONpayload may look something like this:
{
"employees": [
{
"name": "James",
"email": "james.notmyemail@gmail.com"
},
{
"name": "Lea",
"email": "lea.dontemailme@gmail.com"
}
]
}
Another common data structure used by RESTful services is Extensible Markup Language (XML), whichencodes documents in a human and machine-readable format. XML is considerably more verbose than JSON. The same data structure that was shown in the previous example, but in XML, would look something like this:
<employees>
<employee>
<name>James</name>
<email>james.notmyemail@gmail.com</email>
</employee>
<employee>
<name>Lea</name>
<email>lea.dontemailme@gmail.com</email>
</employee>
</employees>
When obtaining a JSON payload, we essentially receive a string. To convert that string into a data object, we have a few options, with the most popular ones being libraries such as Gson, Jackson, and Moshi. In Java, we also have the built-in org.json package, while in Kotlin, we have Kotlin Serialization. We will be using the Kotlin Serialization library. Like Ktor, it was developed by JetBrains. It is very lightweight and well-maintained.
Now that we know what type of data we can commonly expect to use when communicating with network APIs, let’s see how we can communicate with these APIs.
We will use The Cat API. This RESTful API offers us vast data about, well… cats.
To get started, we will create a new project. To allow our app to make network calls, we have to grant our app the internet access install-time permission. We can do this by adding the following code to your AndroidManifest.xml file, right before the Application tag:
<uses-permission android:name="android.permission.INTERNET" />
Next, we need to set up our app so that it includes Ktor. Ktor helps us generate Uniform Resource Locators (URLs), whichare the addresses of the server endpoints we want to access. It also makes decoding JSON payloads into Kotlin data structures easier by providing integration with several parsing libraries. Sending data to the server is also easier with Ktor, as it helps with encoding the requests from Kotlin data structures into JSON.
To add Ktor to our project, we need to add the following dependencies to the build.gradle file of our app:
"io.ktor:ktor-client-core:(latest version)"
"io.ktor:ktor-client-cio:(latest version)"
The first line adds the main client functionality to our project, while the second line adds the CIO engine. Engines are Ktor’s mechanism for processing network requests. Different engines allow Ktor to run on different platforms. The CIO engine is a good choice for us because it supports Android, as well as Java virtual machines and native Kotlin.
With Ktor included in our project, we can set the project up.
To access an HTTP(S) endpoint, we must start by creating a Ktor HttpClient instance. To create a client, we must provide an engine. The code to create a client with the CIO engine looks like this:
val client = HttpClient(CIO)
The preceding code is quite self-explanatory and produces a client that we can use to make network requests.
In Android, network requests cannot be made from the main thread. This makes sense because waiting for a network request to resolve is an expensive operation, and executing it from the main thread would make an app non-responsive.
Ktor solves this problemby using coroutines. This means that network calls using a Ktor client must either be in a suspend function or within a coroutine. For example, to make a call to the https://api.thecatapi.com/v1/images/search endpoint, we can use the following code:
suspend fun searchImages(limit: Int, size: String):
String =
client.get(
https://api.thecatapi.com/v1/images/search
) {
url {
parameter("limit", limit)
}
}.body()
There are a few things to note here. First, you will notice that the searchImages function is a suspend function. This is required to make sure we don’t block the main thread when making a network call. Next, you will notice we call the get function of the client. This performs a GET operation. The get function has several overloads. The one we used here takes two arguments: a URL string and a lambda.
The lambda we pass to the get function lets us configure the request. In our case, we use a url block to add a parameter to the request. There are different ways in which we can transfer data to the API. Adding parameters by calling parameter, as we did here, is one such way. It allows us to define values that have been added to the query of our request URL (the optional part of a URL that comes after the question mark). The parameter function takes a key and a value. The key is a string, and the value can be any value. Under the hood, a null value will be ignored, and toString() will be called on any other value before it is added to the query string. Any non-null value passed to parameter will be URL-encoded for us. In our case, we added a limit to the query string.
Ktor also provides functions for all other HTTP operations, including post, put, patch, and delete. These are all convenient extension functions that can be used on top of request, which allows you to set the request method explicitly. By providing a lambda to these functions, we can configure the request URL, method, headers, and body.
Going back to our example, our final call is to body. This function returns the server response and returns a value of a generic type. To keep things simple at this stage, we accepted the response as a string. We did this by declaring that the return type of searchImage be a string and relying on Kotlin’s ability to infer the type for body.
So, where should we implement the Ktor code? In both clean architecture and Google’s architecture (note that the two are not the same), data is provided by repositories. Repositories, in turn, contain data sources. One such data source could be a network data source. This is where we will implement our network calls. Our ViewModel objects will then request data from repositories via use case classes.
Important note
In the caseof Model-View-ViewModel (MVVM), ViewModel is an abstraction of the view that exposes properties and commands.
For our implementation, we will simplify the process by instantiating the Ktor client and making the get call in the Activity class. This is not a good practice. Do not do this in a production app. It does not scale well and is very difficult to test. Instead, adopt an architecture that decouples your views from your business logic and data.
If you want to learn more about Android and its functions, then How to Build Android Applications with Kotlin is the book for you!