Intercepting Ktor Network Responses in Kotlin Multiplatform

Thomas Kioko™
ProAndroidDev
Published in
3 min readJul 25, 2023

--

Photo by Omar Flores on Unsplash

Introduction:

Handling various HTTP response codes is crucial when building mobile applications that communicate with APIs. This article will explore how to use Ktor’s `HttpResponseValidator` to intercept and handle responses in mobile applications.

We’ll use Trakt as a use case since it’s what I am for my project, but the concept should work for any API. One of the status codes from Trakt is `403` (Forbidden), which indicates that the server understands the request but refuses to authorize it. We’ll see how we can intercept such responses, format the message and present this to the user.

Below is what we’ll be able to achieve at the end of this. 😎

TL;DR

If you just want to look at the code, click the link below.

Understanding HttpResponseValidator

Ktor is a robust Kotlin-based framework for building server-side and client-side applications. It provides a flexible and extensible architecture to efficiently handle HTTP requests and responses. One of the key components in Ktor is the `HttpResponseValidator,` which allows developers to define a custom response.

Intercepting Responses

To intercept responses, we need to add `HttpResponseValidator` inside the HttpClient’s body Ktor’s to check the response’s status code and take appropriate action. Before doing that, we need to enable default validation by setting the `expectSuccess` property to `true.` This terminates `HttpClient.receivePipeline` if the status code is unsuccessful.

Here’s our custom exception class.

API Response Wrapper

With the HttpResponseValidator in place, we can create an extension function to wrap API responses.

You can also use kotlin-result or Arrow’s Either depending on your needs. In this case, we will create our class. `ApiResponse`

API Requests

We can now create a function with a return type `ApiResonse<T>` and use the extension function we created to make the API call.

You can now invoke the Api call and handle the response based on your implementation. In my case, I am using Store5. (Blog coming soon). We make the API call inside the `fetcher.` If successful, cache it else, throw an exception.

By doing this, Store will wrap the exception in the `StoreReadResponse.Error` type, ensuring the flow does not break the stream and will still receive updates when data changes. We can now propagate the result and handle it in the presentation layer. In this case, when we get an exception, we show a SnackBar.

Exception Snackbar

And that’s it! 🎊 I hope this post helped. If you liked it, give it some claps! 👏

--

--