HTTP Requests with Kotlin and khttp

Table of Contents

Introduction to khttp

khttp is a lightweight and user-friendly HTTP client library for Kotlin that simplifies making HTTP requests. It provides a more intuitive and concise syntax compared to the standard Java HTTP libraries. khttp is built on top of the Apache HttpClient library and allows you to perform various types of HTTP requests easily.

In this article, we will explore how to use khttp to make HTTP requests in Kotlin.

Setting Up khttp in Your Project

Before you can start using khttp in your Kotlin project, you need to add the khttp library as a dependency. If you are using Gradle, add the following line to your build.gradle.kts file:

implementation("io.github.khttp:khttp:1.0.0")

If you are using Maven, add the following XML snippet to your pom.xml file:

<dependency>
    <groupId>io.github.khttp</groupId>
    <artifactId>khttp</artifactId>
    <version>1.0.0</version>
</dependency>

After adding the dependency, sync or rebuild your project to include the khttp library.

Making HTTP GET Requests

To make an HTTP GET request using khttp, you simply need to call the get function and pass the URL of the resource you want to access. The response returned by the get function contains all the information about the response, including the status code, headers, and content.

Let’s see how to make a simple GET request with khttp:

import khttp.get

fun main() {
    val url = "https://jsonplaceholder.typicode.com/posts/1"
    val response = get(url)

    if (response.statusCode == 200) {
        println("Response Body:")
        println(response.text)
    } else {
        println("HTTP request failed with status code: ${response.statusCode}")
    }
}

In this example, we import the khttp.get function, which allows us to make a GET request. We specify the URL “https://jsonplaceholder.typicode.com/posts/1” to retrieve a sample JSON data. The response is then checked for a successful status code (200) before printing the response body.

Making HTTP POST Requests

Making an HTTP POST request with khttp is also straightforward. You can use the post function and provide the URL and data to be sent in the request body.

Let’s make a POST request to send JSON data to a server:

import khttp.post

fun main() {
    val url = "https://jsonplaceholder.typicode.com/posts"
    val data = mapOf("title" to "New Post", "body" to "This is the body of the new post.", "userId" to 1)
    val response = post(url, json = data)

    if (response.statusCode == 201) {
        println("Post created successfully!")
        println("Response Body:")
        println(response.text)
    } else {
        println("HTTP request failed with status code: ${response.statusCode}")
    }
}

In this example, we use the khttp.post function and specify the URL “https://jsonplaceholder.typicode.com/posts” to create a new post. We provide the JSON data to be sent in the request body using a Map. The response is then checked for a successful status code (201) before printing the response body.

Handling Errors and Exceptions

It’s essential to handle errors and exceptions properly when making HTTP requests. khttp throws various exceptions, such as khttp.exceptions.HttpException and khttp.exceptions.ConnectException, which you should catch and handle accordingly.

Here’s an example of handling exceptions with khttp:

import khttp.get
import khttp.exceptions.HttpException
import khttp.exceptions.ConnectException

fun main() {
    val url = "https://jsonplaceholder.typicode.com/posts/1000"

    try {
        val response = get(url)
        println("Response Body:")
        println(response.text)
    } catch (e: HttpException) {
        println("HTTP request failed with status code: ${e.response.statusCode}")
    } catch (e: ConnectException) {
        println("Failed to connect to the server: ${e.message}")
    }
}

In this example, we attempt to make an HTTP GET request to a non-existing resource “https://jsonplaceholder.typicode.com/posts/1000”. The HttpException will be caught and the status code of the failed response will be printed. If there is a connection error, the ConnectException will be caught and the error message will be displayed.

Handling Response Data with khttp

In addition to making HTTP requests, khttp provides convenient methods to handle response data. Let’s explore some useful features for handling response data with khttp.

JSON Response Handling

khttp includes built-in support for handling JSON responses. When the server responds with JSON data, khttp can automatically parse the JSON and provide it as a Map<String, Any> or a List<Any> for easier access.

Here’s an example of handling a JSON response with khttp:

import khttp.get

fun main() {
    val url = "https://jsonplaceholder.typicode.com/posts/1"
    val response = get(url)

    if (response.statusCode == 200) {
        val post = response.jsonObject
        println("Title: ${post["title"]}")
        println("Body: ${post["body"]}")
    } else {
        println("HTTP request failed with status code: ${response.statusCode}")
    }
}

In this example, we use the response.jsonObject property to automatically parse the JSON response. We can then access the values using the keys, making it easy to work with JSON data in Kotlin.

Binary Response Handling

khttp also supports handling binary responses, such as downloading files from the server. The response.content property provides access to the raw binary data as a ByteArray.

Here’s an example of downloading an image file using khttp:

import khttp.get
import java.io.File

fun main() {
    val url = "https://example.com/image.jpg"
    val response = get(url)

    if (response.statusCode == 200) {
        val file = File("downloaded_image.jpg")
        file.writeBytes(response.content)
        println("Image downloaded successfully.")
    } else {
        println("HTTP request failed with status code: ${response.statusCode}")
    }
}

In this example, we use the response.content property to access the binary data of the image. We then write the binary data to a local file named “downloaded_image.jpg” using File.writeBytes().

Custom Headers and Query Parameters

khttp allows you to set custom headers and query parameters for your HTTP requests. This is useful when working with APIs that require authentication or specific request headers.

Here’s an example of setting custom headers and query parameters with khttp:

import khttp.get

fun main() {
    val url = "https://api.example.com/data"
    val headers = mapOf("Authorization" to "Bearer your_access_token", "User-Agent" to "MyApp/1.0")
    val params = mapOf("page" to "1", "limit" to "10")

    val response = get(url, headers = headers, params = params)

    if (response.statusCode == 200) {
        println("Response Body:")
        println(response.text)
    } else {
        println("HTTP request failed with status code: ${response.statusCode}")
    }
}

In this example, we use the headers parameter to set custom headers, such as an “Authorization” header with an access token. We also use the params parameter to set query parameters, such as “page” and “limit”. These parameters are automatically appended to the URL.

Conclusion

khttp is a versatile and straightforward HTTP client library for Kotlin that simplifies making HTTP requests and handling responses. By incorporating khttp into your Kotlin projects and utilizing its features for handling JSON, binary data, custom headers, and query parameters, you can efficiently interact with web services and APIs. With the concise and intuitive syntax of khttp, developers can focus on building robust and reliable applications that communicate seamlessly with remote resources.

Command PATH Security in Go

Command PATH Security in Go

In the realm of software development, security is paramount. Whether you’re building a small utility or a large-scale application, ensuring that your code is robust

Read More »
Undefined vs Null in JavaScript

Undefined vs Null in JavaScript

JavaScript, as a dynamically-typed language, provides two distinct primitive values to represent the absence of a meaningful value: undefined and null. Although they might seem

Read More »