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.