DEV Community

Andrii Maliuta
Andrii Maliuta

Posted on

HTTP Client UI with Kotlin and JavaFX

Sometimes it can be useful to use some UI to perform HTTP requests and not just CLI tools. Od course, there are tools like Postamn or Insomnia and they are great, but it can be good to have some very simple own UI to do this and test some simple thinsgs :)

Code on Github: https://github.com/ahndmal/http-client-ktl-jfx.

We will use Kotlin (https://kotlinlang.org) and OpenJFX (https://openjfx.io) and Gradle to build the app (though javac / kotlinc can be enough).

We add "org.openjfx.javafxplugin" Gradle plugin to build.gradle.kts and add basic configuration:

plugins {
    kotlin("jvm") version "1.9.0"
    application
    **id("org.openjfx.javafxplugin") version "0.0.13"**
}

javafx {
    setVersion("20")
    setModules(listOf("javafx.controls"))
}

group = "com.andmal"
version = "0.0.2"

repositories {
    mavenCentral()
}

kotlin {
    jvmToolchain(20)
}

application {
    mainClass.set("Main")
}

Enter fullscreen mode Exit fullscreen mode

Also, we create Main.kt file to add the basic logic to initiate UI with JavaFX library.

JavaFX UI elements structure

class Main : Application() {
    override fun start(primaryStage: Stage?) {
        val scene = Scene(createContent(), 1200.0, 900.0)
        primaryStage?.title = "HTTP Client"
        primaryStage?.scene = scene
        primaryStage?.show()
    }
}
Enter fullscreen mode Exit fullscreen mode

The Main class extends the javafx.application.Application and implements the start method to initiate the UI. We add the createContent() method as the parameter to start method and add the basic logic to it:

private fun createContent(): Parent {
   // todo
}
Enter fullscreen mode Exit fullscreen mode

Basic UI window

To combine the UI we can use basic VBox / HBox classes for vertical and horizonal alignment of elemtns and also GridPane to map the items by rows and columns.

We add basic UI elements:

val mainBox = VBox()
val requestBox = VBox()
val reqPane = GridPane()
val reqBody = TextArea()

// response 
val responsePane = GridPane()
val responseBox = VBox()
val urlLabel = Label("URL")
urlField = TextField()
Enter fullscreen mode Exit fullscreen mode

Add some padding and background:

mainBox.padding = Insets(10.0)
requestBox.border = Border.stroke(Paint.valueOf("orange"))
HBox.setMargin(requestBox, Insets(10.0))
reqBody.minWidth = 500.0
reqBody.minHeight = 200.0
Enter fullscreen mode Exit fullscreen mode

Then we add buttons, headers to the core elements:

reqPane.add(methodType, 0, 2)
reqPane.add(urlField, 1, 2)
reqPane.add(reqButton, 2, 2)
reqPane.add(reqHeaderButton, 2, 3)

requestBox.children.add(reqPane)
responseBox.children.add(responsePane)

mainBox.children.addAll(
    requestBox, responseBox
)
Enter fullscreen mode Exit fullscreen mode

Add listeners to buttons to react to clicking on it:

reqButton.setOnMouseClicked { event ->
     if (urlField.length == 0) {
           infoHeader.text = "Error: please fill in URL"
           infoHeader.background = Background.fill(Paint.valueOf("red"))
           infoHeader.textFill = Paint.valueOf("white")
           infoHeader.font = Font.font(17.0)
           responsePane.add(infoHeader, 0, 0)
            } else {
                // correct request data
             responseBox.children.removeAll()
     }
}
Enter fullscreen mode Exit fullscreen mode

Also, we add "Save file" button to save the response as a file:

saveAsFileBtn.setOnMouseClicked {
    val file = 
Files.createFile(Path.of("./response_${Instant.now().epochSecond}"))
                    file.writeBytes(httpResponse.body().toByteArray())
}
Enter fullscreen mode Exit fullscreen mode

We use java.net.http.CLient (available since Java v.11) as simple and basic HTTP client:

// HTTP client
val client = HttpClient.newBuilder()
      .version(HttpClient.Version.HTTP_1_1).build()

// request
val req = HttpRequest.newBuilder()
   .uri(URI.create(urlField.text))
Enter fullscreen mode Exit fullscreen mode

We want to have some text field for body when using POST or PUT methods:

methodType.setOnAction {
    when (methodType.value.first) {
       "GET" -> reqPane.children.remove(reqBody)
       "POST" ->  reqPane.add(reqBody, 1, 3)
       "PUT" ->  reqPane.add(reqBody, 1, 3)
    }
}
Enter fullscreen mode Exit fullscreen mode

Complete building HTTP request depending on what HTTP method we select:

when(methodType.value.second) {
   "GET" -> req.GET()
   "POST" -> req.POST(BodyPublishers.ofString(reqBody.text))
   "PUT" -> req.PUT(BodyPublishers.ofString(reqBody.text))
   "DELETE" -> req.DELETE()
}
Enter fullscreen mode Exit fullscreen mode

So we have request section with:

  1. Select of reqest type
  2. URL field
  3. Send button to send request

Response:

  1. Text area to show response body
  2. Headers and Status buttons to show additional data when clicking them

Run the app:

Complete UI

Top comments (1)

Collapse
 
parzival_computer profile image
Parzival

Good job.