0

I'm new to Kotlin language and I would like to know if it's a good practice have a chain of scope functions. As example, I'm writing a function that calls some API (an utilitary function), parse the string response to specific object, do a small verification and return an object.

Is a good practice have a chain of scope functions like this code above?

    fun execRequest(endpoint: String, method: String = "GET", body: String? = ""): String =
            defaultHttpRequestBuilder()
                    .uri(URI.create(endpoint))
                    .method(method, HttpRequest.BodyPublishers.ofString(body))
                    .header("Content-Type", "application/x-www-form-urlencoded")
                    .build()
                    .run { httpClient.send(this, HttpResponse.BodyHandlers.ofString()) }
                    .let { it.body() }

    fun processLoginRequest(challenge: String) =
            execRequest(buildEndpoint("login", challenge))
                    .let {
                        mapper.readValue<LoginResponse>(it)
                    }
                    .let {
                        val authSituation = Auth(it.skip, it.challenge)
                        if (it.skip) {
                            val acceptResponse = acceptLoginRequest(challenge, it.subject)
                            authSituation.redirectTo = acceptResponse.redirectTo
                        }
                        authSituation
                    }

This code looks awful in my opinion. Is there another way to write it in a "Kotlin way"?

3
  • 3
    Just because you can, doesn't mean you should. I agree the above code looks awful. It's hard to follow what's happening because it relies on so many different receivers and implicit parameters. You can break these up by assigning results to variables before continuing with that variable on the next line. But this question cannot really be answered without opinion. Commented May 18, 2020 at 20:47
  • How do you suggest break this code? I like your point of view but not sure how to do it without make a lot of variables Commented May 18, 2020 at 20:53
  • 2
    There's nothing wrong with making a lot of variables if it makes your code more readable. Commented May 18, 2020 at 21:14

1 Answer 1

2

I think this question is likely to be closed due to answers being a matter of opinion, but since you asked about my comment, here is how you could break up the first function.

fun execRequest(endpoint: String, method: String = "GET", body: String? = ""): String {
    val request = defaultHttpRequestBuilder()
        .uri(URI.create(endpoint))
        .method(method, HttpRequest.BodyPublishers.ofString(body))
        .header("Content-Type", "application/x-www-form-urlencoded")
        .build()
    val response = httpClient.send(request, HttpResponse.BodyHandlers.ofString())
    return response.body()
}

I might break up the second function like this

fun processLoginRequest(challenge: String): Auth {
    val httpResponse = execRequest(buildEndpoint("login", challenge))
    val loginResponse: LoginResponse = mapper.readValue(httpResponse)
    return Auth(loginResponse.skip, loginResponse.challenge)
        .apply {
            if (loginResponse.skip) 
                redirectTo = acceptLoginRequest(challenge, it.subject).redirectTo
        }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.