diff --git a/openai-java-client-okhttp/build.gradle.kts b/openai-java-client-okhttp/build.gradle.kts index 9f10f7968..2cc49dc85 100644 --- a/openai-java-client-okhttp/build.gradle.kts +++ b/openai-java-client-okhttp/build.gradle.kts @@ -21,7 +21,7 @@ listOf(configurations.testCompileClasspath, configurations.testRuntimeClasspath) dependencies { api(project(":openai-java-core")) - implementation("com.squareup.okhttp3:okhttp:4.12.0") + api("com.squareup.okhttp3:okhttp:4.12.0") testImplementation(kotlin("test")) testImplementation("org.assertj:assertj-core:3.27.7") diff --git a/openai-java-client-okhttp/src/main/kotlin/com/openai/client/okhttp/OkHttpClient.kt b/openai-java-client-okhttp/src/main/kotlin/com/openai/client/okhttp/OkHttpClient.kt index 5a034f7bd..1d5e12fd3 100644 --- a/openai-java-client-okhttp/src/main/kotlin/com/openai/client/okhttp/OkHttpClient.kt +++ b/openai-java-client-okhttp/src/main/kotlin/com/openai/client/okhttp/OkHttpClient.kt @@ -29,6 +29,7 @@ import okhttp3.ConnectionPool import okhttp3.Dispatcher import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.Interceptor import okhttp3.MediaType import okhttp3.MediaType.Companion.toMediaType import okhttp3.Request @@ -120,6 +121,7 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null + private val interceptors: MutableList = mutableListOf() fun timeout(timeout: Timeout) = apply { this.timeout = timeout } @@ -136,6 +138,9 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie this.proxyAuthenticator = proxyAuthenticator } + /** Adds an application interceptor to the underlying OkHttp transport. */ + fun addInterceptor(interceptor: Interceptor) = apply { interceptors.add(interceptor) } + /** * Sets the maximum number of idle connections kept by the underlying [ConnectionPool]. * @@ -187,6 +192,8 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie .callTimeout(timeout.request()) .proxy(proxy) .apply { + interceptors.forEach(::addInterceptor) + proxyAuthenticator?.let { auth -> proxyAuthenticator { route, response -> auth diff --git a/openai-java-client-okhttp/src/test/kotlin/com/openai/client/okhttp/OkHttpClientTest.kt b/openai-java-client-okhttp/src/test/kotlin/com/openai/client/okhttp/OkHttpClientTest.kt index b202c83c6..ba7413bac 100644 --- a/openai-java-client-okhttp/src/test/kotlin/com/openai/client/okhttp/OkHttpClientTest.kt +++ b/openai-java-client-okhttp/src/test/kotlin/com/openai/client/okhttp/OkHttpClientTest.kt @@ -5,6 +5,7 @@ import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo import com.github.tomakehurst.wiremock.junit5.WireMockTest import com.openai.core.http.HttpMethod import com.openai.core.http.HttpRequest +import okhttp3.Interceptor import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -41,4 +42,40 @@ internal class OkHttpClientTest { // Should have cancelled the underlying call assertThat(call.isCanceled()).isTrue() } + + @Test + fun execute_runsConfiguredApplicationInterceptor() { + stubFor(get(urlPathEqualTo("/something")).willReturn(ok())) + val client = + OkHttpClient.builder() + .addInterceptor( + Interceptor { chain -> + chain.proceed( + chain + .request() + .newBuilder() + .header("X-Test-Interceptor", "applied") + .build() + ) + } + ) + .build() + + client + .execute( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(baseUrl) + .addPathSegment("something") + .build() + ) + .use { assertThat(it.statusCode()).isEqualTo(200) } + + verify( + 1, + getRequestedFor(urlPathEqualTo("/something")) + .withHeader("X-Test-Interceptor", equalTo("applied")), + ) + client.close() + } }