Kotlin scripts and the terminal

Kotlin scripts and the terminal

Run Kotlin scripts from the terminal.

in
Table of contents

Similarly, you can create scripts with Bash, it is possible to do that with Kotlin too. You can pass arguments or even add dependencies from maven repositories.

In the next example, we are going to do everything mentioned above by adding OkHttp to do an HTTP request to the Rick And Morty API and using Moshi to transform from JSON to Kotlin classes.

Create a Kotlin script

Just create a file named rick-and-morty.main.kts. If you open it with IntelliJ IDEA, code highlighting will work, including any imported dependency, so it is easier to create the script using the autocomplete.

Add dependencies

This is even easier than adding dependencies in Gradle. The annotation DependsOn accepts a String as the argument so you can add whatever dependencies you need at the top of the script.

@file:DependsOn("com.squareup.moshi:moshi:1.13.0")
@file:DependsOn("com.squareup.moshi:moshi-kotlin:1.13.0")
@file:DependsOn("com.squareup.okhttp3:okhttp:4.9.3")

Get the arguments

The script is going to receive the character ID to use it within the HTTP request to the API. This ID is an integer number. Also, we are going to check if this value is correct, and if it is not correct, we will show an error.

val id: Int =
    checkNotNull(args.firstOrNull()?.toIntOrNull()) {
        "ID is required and must be `Int`"
    }

args is a list of strings (List<String>).

HTTP request

As this is not a tutorial about OkHttp or Moshi, you can see the whole code. If you are interested in learning those libraries, check their respective GitHub repositories.

val client = OkHttpClient()

val request: Request =
    Request
        .Builder()
        .url("https://rickandmortyapi.com/api/character/$id")
        .build()

val moshi: Moshi =
    Moshi
        .Builder()
        .addLast(KotlinJsonAdapterFactory())
        .build()

val jsonAdapter: JsonAdapter<Character> = moshi.adapter(Character::class.java)

client.newCall(request).execute().use { response ->
    val content: String? = response.body?.string()
    if (response.code == 200 && content != null) {
        val character = jsonAdapter.fromJson(content)
        println(character)
    }
}

data class Character(
    val id: Int,
    val name: String,
    val status: String, val species: String,
)

Run the script

kotlin rick-and-morty.main.kts 20

20 is the character ID, you can pass whatever integer number.

It is possible to pass multiple elements, separated by spaces (that is the reason args is a list), but in our case, we only need one argument.

The script returns:

Character(id=20, name=Ants in my Eyes Johnson, status=unknown, species=Human)

Conclusion

It is simple and useful to create scripts with Kotlin, even adding dependencies, personally, I use to edit a lot of files when I haven’t Gradle so I can’t create Gradle tasks for that.

The whole code in this example:

@file:DependsOn("com.squareup.moshi:moshi:1.13.0")
@file:DependsOn("com.squareup.moshi:moshi-kotlin:1.13.0")
@file:DependsOn("com.squareup.okhttp3:okhttp:4.9.3")

import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import okhttp3.OkHttpClient
import okhttp3.Request

val id: Int =
    checkNotNull(args.firstOrNull()?.toIntOrNull()) {
        "ID is required and must be `Int`"
    }

val client = OkHttpClient()

val request: Request =
    Request
        .Builder()
        .url("https://rickandmortyapi.com/api/character/$id")
        .build()

val moshi: Moshi =
    Moshi
        .Builder()
        .addLast(KotlinJsonAdapterFactory())
        .build()

val jsonAdapter: JsonAdapter<Character> = moshi.adapter(Character::class.java)

client.newCall(request).execute().use { response ->
    val content: String? = response.body?.string()
    if (response.code == 200 && content != null) {
        val character = jsonAdapter.fromJson(content)
        println(character)
    }
}

data class Character(
    val id: Int,
    val name: String,
    val status: String, val species: String,
)