Kotlin scripts y la terminal

Kotlin scripts y la terminal

Ejecuta scripts escritos en Kotlin desde la terminal.

en
Tabla de contenidos

Al igual que pueden crearse scripts con Bash, también es posible hacerlo con Kotlin y ejecutarlos desde la terminal. Puedes pasar argumentos y utilizar dependencias publicadas en repositorios maven.

En el siguiente ejemplo vamos a ver cómo hacer todo lo mencionado anteriormente, añadiendo OkHttp para hacer una petición a la API de Rick and Morty y Moshi para transformar los diferentes JSON a clases de Kotlin.

Crear un script de Kotlin

Simplemente crea un fichero llamado rick-and-morty.main.kts. Si lo abres desde IntelliJ IDEA, obtendrás code highlighting, incluyendo de las dependencias que has añadido, siendo más fácil crear el script utilizando el autocompletado.

Añadir dependencias

Es más sencillo incluso que en Gradle añadir cualquier dependencia a un script, simplemente en la parte superior se puede utilizar la anotación DependsOn y se le pasa como argumento la dependencia en cuestión.

@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")

Obtener los argumentos

El script va a recibir la identidad del personaje a obtener de la API, el cual es un número entero. Además se va a comprobar si dicho valor es correcto, y si no, se mostrará un error.

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

args es una lista de strings (List<String>).

Petición http

Como esto no es un tutorial sobre OkHttp o Moshi, puedes ver el código de la petición completo a continuación. Si te interesa profundizar más en dichas dependencias, visita sus respectivos repositorios de GitHub.

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,
)

Ejecutar el script

kotlin rick-and-morty.main.kts 20

20 es la identidad del personaje, puedes pasar cualquier número entero.

Se podrían pasar varios elementos separados por espacios (de ahí que args sea una lista), pero en nuestro caso solo necesitamos pasar uno.

El script devolverá el resultado:

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

Conclusión

Es muy sencillo y muy útil montar scripts en Kotlin incluso utilizando dependencias, personalmente los suelo utilizar para editar archivos en masa bastante a menudo cuando no puedo hacer una tarea de Gradle.

El código completo del ejemplo lo puedes ver a continuación:

@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,
)