The following example route, does an http call to ...
# ktor
j
The following example route, does an http call to one of its own routes. This http call goes through the full network stack. What are the options for bypassing the http stack when executing requests against itself, like testApplication: https://ktor.io/docs/server-testing.html#add-dependencies fun Application.configureRouting() { val client = HttpClient { defaultRequest { host = “0.0.0.0” port = 8080 } engine { proxy = ProxyBuilder.http(“http://127.0.0.1:8888”) } } routing { get(“/”) { val t = client.get(“https://www.google.com”).bodyAsText() call.respondText(t) } get(“/sayHello/{name}“) { call.respondText(“Hello ${call.parameters[“name”]}“) } get(“/helloService/{name}“) { // This httpcall calls the above route (a call within the same process) val response = client.get(“/sayHello/${call.parameters[“name”]}“).bodyAsText() call.respondText(response) } } }
🧵 1
a
You can use the external services API to mock the external endpoints. However, you need to reorganize your code to make the client instance injectable into the
configureRouting
method to pass the test client within the
testApplication
.
j
Thanks. I looked at the external service api but in this case I do not want to mock the endpoint but actually call the internal endpoint in mu own application using http (and not a direct dependency on a class/interface which is of course possible because it is the same application). The http call works but does a network roundtrip (on localhost), when inspecting the request with for example Charles proxy. I wonder if it is possible to execute this http request which is internal to my application and bypass the network stack (just like testApplication does).
a
Then, you need to simply use the test client within the route handlers.
j
I am going to take a look at that! Any idea how to obtain this testclient within main application code?
a
You can pass the instance from the
testApplication
block down to the method that configures the routing.
j
Something like this you mean?
Copy code
fun main() {
    embeddedServer(CIO, port = 8082, host = "0.0.0.0", module = Application::module)
        .start(wait = true)
}

fun Application.module() {
    testApplication {
        this@module.configureRouting(client)
    }
}
I do get an error if I try it like this:
2024-10-07 10:52:08.790 [DefaultDispatcher-worker-9] DEBUG io.ktor.server.Application - Unhandled: GET - /helloService/jamie. Exception class kotlinx.coroutines.JobCancellationException: Parent job is Completed
kotlinx.coroutines.JobCancellationException: Parent job is Completed
a
No. First, you need to define a parameter of the
HttpClient
type for the
Application.configureRouting
method. Second, when using
embeddedServer
, you need to call the
configureRouting
method with the
HttpClient
instance for the production environment. Within the test, you can pass the test client to the
configureRouting
method.
j
In this case, I don’t want to use this client in a unit test but in the actual application itself (outside of the unit test context). Like calling the http endpoint from within the producten app, so that it bypasses the network stack in the production app itself.
a
You can't bypass the network stack using the HTTP client within the production app. What is the purpose of making a request to the server within the server?
j
I have a multi-module Gradle project build with Ktor. Each submodule is independent of each other (except some common modules). You can think of it as a domain oriented micro-services approach within a monolithic application. The application is deployed as a single deployable unit (in a container). Dependencies between modules can exists on the external interface level. By leveraging the same transport as clients do, HTTP in this case, I get the cleanest separation. With this in place (every module also has its own database schema with no foreign key constraints between each schema), I have the option to deploy a module in its own container. Effectively breakup u the monilith in multiple deployable units without any code changes. It does work atm but the ‘local’ http call does has some network overhead. This is a tradoff (compared to calling a Koltin interface directly.), so trade-in some performance for flexibility. My next option was to research the option to bypass the network stack when modules are deployed within the same container. Of course, when a module is deployed as a separate container, the http call will be a network call. Hope this clarifies.