En el pasado post vimos cómo consumir un servicio Node desde una aplicación Java gracias a la librería OkHttp. Esta vez usaremos Kotlin como lenguaje base y Gradle para la administración de las dependencias y ejecución del proyecto.
¿Qué haremos?
- Crear una aplicación Kotlin con Gradle.
- Consumir una API pública: https://api.chucknorris.io/jokes/random
1. Comenzaremos con la creación del directorio del proyecto:
$ mkdir proyecto-kotlin $ cd proyecto-kotlin
El directorio del proyecto se verá así:
proyecto-kotlin/ .gitattributes .gitignore .gradle .kotlin app/ build/ gradle/ gradle.properties gradlew gradlew.bat settings.gradle.kts
2. Agregamos la dependencia de ``OkHttp`` en el archivo ``build.gradle.kts``:
plugins { alias(libs.plugins.kotlin.jvm) application } repositories { mavenCentral() } dependencies { implementation("com.squareup.okhttp3:okhttp:4.12.0") // Moved to implementation testImplementation("org.jetbrains.kotlin:kotlin-test") testImplementation(libs.junit.jupiter.engine) testRuntimeOnly("org.junit.platform:junit-platform-launcher") implementation(libs.guava) testImplementation("org.junit.jupiter:junit-jupiter:5.10.3") testImplementation("org.mockito:mockito-core:5.12.0") testImplementation("org.mockito:mockito-junit-jupiter:5.12.0") } java { toolchain { languageVersion = JavaLanguageVersion.of(21) } } application { mainClass = "org.inforhomex.AppKt" } tasks.named<Test>("test") { useJUnitPlatform() }
Con esto se podrá descargar la dependencia.
3. Editamos el programa ``app/src/main/kotlin/org/inforhomex/App.kt``.
package org.inforhomex import okhttp3.OkHttpClient import okhttp3.Request import java.io.IOException private const val URL_API = "https://api.chucknorris.io/jokes/random" fun run(client: OkHttpClient = OkHttpClient()) { val request = Request.Builder().url(URL_API).build() client.newCall(request).execute().use { response -> if (!response.isSuccessful) throw IOException("Unexpected code $response") for ((name: String, value: String) in response.headers) { println("$name: $value") } println(response.body?.string() ?: "No response body") } } fun main() { run() }
4. Creamos una prueba unitaria ``AppTest.kt``
package org.inforhomex import okhttp3.* import okio.Buffer import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.mockito.Mock import org.mockito.Mockito import org.mockito.junit.jupiter.MockitoExtension import java.io.IOException import kotlin.test.assertEquals import kotlin.test.assertFailsWith @ExtendWith(MockitoExtension::class) class AppTest { @Mock private lateinit var client: OkHttpClient @Mock private lateinit var response: Response @Mock private lateinit var responseBody: ResponseBody @Mock private lateinit var call: Call private val urlApi = "https://api.chucknorris.io/jokes/random" @BeforeEach fun setUp() { Mockito.`when`(client.newCall(Mockito.any(Request::class.java))).thenReturn(call) } @Test fun `test run success response`() { val mockJson = """ { "icon_url": "https://assets.chucknorris.host/img/avatar/chuck-norris.png", "id": "abc123", "url": "", "value": "Chuck Norris can divide by zero." } """ Mockito.`when`(call.execute()).thenReturn(response) Mockito.`when`(response.isSuccessful).thenReturn(true) Mockito.`when`(response.body).thenReturn(responseBody) Mockito.`when`(responseBody.string()).thenReturn(mockJson) Mockito.`when`(response.headers).thenReturn(Headers.Builder().add("Content-Type", "application/json").build()) val output = captureOutput { run(client) } assert(output.contains("Content-Type: application/json")) assert(output.contains("Chuck Norris can divide by zero.")) } @Test fun `test run unsuccessful response throws IOException`() { Mockito.`when`(call.execute()).thenReturn(response) Mockito.`when`(response.isSuccessful).thenReturn(false) Mockito.`when`(response.code).thenReturn(404) val exception = assertFailsWith<IOException> { run(client) } assertEquals("Unexpected code 404", exception.message) } private fun captureOutput(block: () -> Unit): String { val outputStream = java.io.ByteArrayOutputStream() val printStream = java.io.PrintStream(outputStream) val originalOut = System.out System.setOut(printStream) try { block() } finally { System.setOut(originalOut) } return outputStream.toString() } }
5. Compilamos y ejecutamos la aplicación:
$ gradle build $ gradle run
Si todo va bien, veremos esto en la consola:
date: Sun, 19 Oct 2025 03:25:17 GMT content-type: application/json nel: {"report_to":"heroku-nel","response_headers":["Via"],"max_age":3600,"success_fraction":0.01,"failure_fraction":0.1} report-to: {"group":"heroku-nel","endpoints":[{"url":"https://nel.heroku.com/reports?s=e%2BRTonTfjrgED0WXfh1o2mxbl6%2BLhQQ4LIu%2F1NhF4MM%3D\u0026sid=812dcc77-0bd0-43b1-a5f1-b25750382959\u0026ts=1760844317"}],"max_age":3600} reporting-endpoints: heroku-nel="https://nel.heroku.com/reports?s=e%2BRTonTfjrgED0WXfh1o2mxbl6%2BLhQQ4LIu%2F1NhF4MM%3D&sid=812dcc77-0bd0-43b1-a5f1-b25750382959&ts=1760844317" server: cloudflare vary: Origin vary: Access-Control-Request-Method vary: Access-Control-Request-Headers via: 1.1 heroku-router cf-cache-status: DYNAMIC cf-ray: 990d2ad69c2f69de-DFW alt-svc: h3=":443"; ma=86400 {"categories":[],"created_at":"2020-01-05 13:42:20.262289","icon_url":"https://api.chucknorris.io/img/avatar/chuck-norris.png","id":"zDUih4UaS82sDRjSX0hlLQ","updated_at":"2020-01-05 13:42:20.262289","url":"https://api.chucknorris.io/jokes/zDUih4UaS82sDRjSX0hlLQ","value":"Chuck Norris always wanted to surf but couldn't. Everytime his board touches the water, the sea parts."}
¡La aplicación ha funcionado correctamente!
Continuaremos con esta serie de ejemplos en próximas entregas.
Enlaces:
https://square.github.io/okhttp/https://www.baeldung.com/guide-to-okhttp
https://ironpdf.com/es/java/blog/java-help/okhttp-java/