Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.75.0"
".": "0.76.0"
}
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
# Changelog

## 0.76.0 (2025-02-06)

Full Changelog: [v0.75.0...v0.76.0](https://github.com/lithic-com/lithic-java/compare/v0.75.0...v0.76.0)

### Features

* **client:** send client-side timeout headers ([#476](https://github.com/lithic-com/lithic-java/issues/476)) ([c0b8b6d](https://github.com/lithic-com/lithic-java/commit/c0b8b6d4c4f8ac3d79010d494b1ea71ea900b201))


### Bug Fixes

* **api:** add missing `@MustBeClosed` annotations ([#479](https://github.com/lithic-com/lithic-java/issues/479)) ([ed2ddd0](https://github.com/lithic-com/lithic-java/commit/ed2ddd05b76a19143f05b2b3e09c2d9c4e4b55dc))
* **api:** switch `CompletableFuture&lt;Void&gt;` to `CompletableFuture<Void?>` ([ed2ddd0](https://github.com/lithic-com/lithic-java/commit/ed2ddd05b76a19143f05b2b3e09c2d9c4e4b55dc))
* **client:** add missing validation calls on response ([ed2ddd0](https://github.com/lithic-com/lithic-java/commit/ed2ddd05b76a19143f05b2b3e09c2d9c4e4b55dc))
* **client:** always provide a body for `PATCH` methods ([ed2ddd0](https://github.com/lithic-com/lithic-java/commit/ed2ddd05b76a19143f05b2b3e09c2d9c4e4b55dc))


### Chores

* **api:** new PaymentEventType for ACH Returns and small updates to 3DS AuthenticationResult ([#478](https://github.com/lithic-com/lithic-java/issues/478)) ([bf2fce6](https://github.com/lithic-com/lithic-java/commit/bf2fce6f9d9d6aae2744bb6fe46b7f138a2b6fec))
* **internal:** minor formatting/style changes ([ed2ddd0](https://github.com/lithic-com/lithic-java/commit/ed2ddd05b76a19143f05b2b3e09c2d9c4e4b55dc))
* **internal:** rename some tests ([ed2ddd0](https://github.com/lithic-com/lithic-java/commit/ed2ddd05b76a19143f05b2b3e09c2d9c4e4b55dc))

## 0.75.0 (2025-01-30)

Full Changelog: [v0.74.0...v0.75.0](https://github.com/lithic-com/lithic-java/compare/v0.74.0...v0.75.0)
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<!-- x-release-please-start-version -->

[![Maven Central](https://img.shields.io/maven-central/v/com.lithic.api/lithic-java)](https://central.sonatype.com/artifact/com.lithic.api/lithic-java/0.75.0)
[![Maven Central](https://img.shields.io/maven-central/v/com.lithic.api/lithic-java)](https://central.sonatype.com/artifact/com.lithic.api/lithic-java/0.76.0)

<!-- x-release-please-end -->

Expand All @@ -19,7 +19,7 @@ The REST API documentation can be found on [docs.lithic.com](https://docs.lithic
### Gradle

```kotlin
implementation("com.lithic.api:lithic-java:0.75.0")
implementation("com.lithic.api:lithic-java:0.76.0")
```

### Maven
Expand All @@ -28,7 +28,7 @@ implementation("com.lithic.api:lithic-java:0.75.0")
<dependency>
<groupId>com.lithic.api</groupId>
<artifactId>lithic-java</artifactId>
<version>0.75.0</version>
<version>0.76.0</version>
</dependency>
```

Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
allprojects {
group = "com.lithic.api"
version = "0.75.0" // x-release-please-version
version = "0.76.0" // x-release-please-version
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,38 +31,11 @@ class OkHttpClient
private constructor(private val okHttpClient: okhttp3.OkHttpClient, private val baseUrl: HttpUrl) :
HttpClient {

private fun getClient(requestOptions: RequestOptions): okhttp3.OkHttpClient {
val clientBuilder = okHttpClient.newBuilder()

val logLevel =
when (System.getenv("LITHIC_LOG")?.lowercase()) {
"info" -> HttpLoggingInterceptor.Level.BASIC
"debug" -> HttpLoggingInterceptor.Level.BODY
else -> null
}
if (logLevel != null) {
clientBuilder.addNetworkInterceptor(
HttpLoggingInterceptor().setLevel(logLevel).apply { redactHeader("Authorization") }
)
}

val timeout = requestOptions.timeout
if (timeout != null) {
clientBuilder
.connectTimeout(timeout)
.readTimeout(timeout)
.writeTimeout(timeout)
.callTimeout(if (timeout.seconds == 0L) timeout else timeout.plusSeconds(30))
}

return clientBuilder.build()
}

override fun execute(
request: HttpRequest,
requestOptions: RequestOptions,
): HttpResponse {
val call = getClient(requestOptions).newCall(request.toRequest())
val call = newCall(request, requestOptions)

return try {
call.execute().toResponse()
Expand All @@ -81,18 +54,18 @@ private constructor(private val okHttpClient: okhttp3.OkHttpClient, private val

request.body?.run { future.whenComplete { _, _ -> close() } }

val call = getClient(requestOptions).newCall(request.toRequest())
call.enqueue(
object : Callback {
override fun onResponse(call: Call, response: Response) {
future.complete(response.toResponse())
}
newCall(request, requestOptions)
.enqueue(
object : Callback {
override fun onResponse(call: Call, response: Response) {
future.complete(response.toResponse())
}

override fun onFailure(call: Call, e: IOException) {
future.completeExceptionally(LithicIoException("Request failed", e))
override fun onFailure(call: Call, e: IOException) {
future.completeExceptionally(LithicIoException("Request failed", e))
}
}
}
)
)

return future
}
Expand All @@ -103,10 +76,37 @@ private constructor(private val okHttpClient: okhttp3.OkHttpClient, private val
okHttpClient.cache?.close()
}

private fun HttpRequest.toRequest(): Request {
private fun newCall(request: HttpRequest, requestOptions: RequestOptions): Call {
val clientBuilder = okHttpClient.newBuilder()

val logLevel =
when (System.getenv("LITHIC_LOG")?.lowercase()) {
"info" -> HttpLoggingInterceptor.Level.BASIC
"debug" -> HttpLoggingInterceptor.Level.BODY
else -> null
}
if (logLevel != null) {
clientBuilder.addNetworkInterceptor(
HttpLoggingInterceptor().setLevel(logLevel).apply { redactHeader("Authorization") }
)
}

val timeout = requestOptions.timeout
if (timeout != null) {
clientBuilder
.connectTimeout(timeout)
.readTimeout(timeout)
.writeTimeout(timeout)
.callTimeout(if (timeout.seconds == 0L) timeout else timeout.plusSeconds(30))
}

val client = clientBuilder.build()
return client.newCall(request.toRequest(client))
}

private fun HttpRequest.toRequest(client: okhttp3.OkHttpClient): Request {
var body: RequestBody? = body?.toRequestBody()
// OkHttpClient always requires a request body for PUT and POST methods.
if (body == null && (method == HttpMethod.PUT || method == HttpMethod.POST)) {
if (body == null && requiresBody(method)) {
body = "".toRequestBody()
}

Expand All @@ -115,9 +115,33 @@ private constructor(private val okHttpClient: okhttp3.OkHttpClient, private val
headers.values(name).forEach { builder.header(name, it) }
}

if (
!headers.names().contains("X-Stainless-Read-Timeout") && client.readTimeoutMillis != 0
) {
builder.header(
"X-Stainless-Read-Timeout",
Duration.ofMillis(client.readTimeoutMillis.toLong()).seconds.toString()
)
}
if (!headers.names().contains("X-Stainless-Timeout") && client.callTimeoutMillis != 0) {
builder.header(
"X-Stainless-Timeout",
Duration.ofMillis(client.callTimeoutMillis.toLong()).seconds.toString()
)
}

return builder.build()
}

/** `OkHttpClient` always requires a request body for some methods. */
private fun requiresBody(method: HttpMethod): Boolean =
when (method) {
HttpMethod.POST,
HttpMethod.PUT,
HttpMethod.PATCH -> true
else -> false
}

private fun HttpRequest.toUrl(): String {
url?.let {
return it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,9 @@ class LithicClientAsyncImpl(
.thenApply { response ->
response
.use { apiStatusHandler.handle(it) }
.apply {
.also {
if (requestOptions.responseValidation ?: clientOptions.responseValidation) {
validate()
it.validate()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,15 +239,14 @@ class LithicClientImpl(
.addPathSegments("v1", "status")
.build()
.prepare(clientOptions, params)
return clientOptions.httpClient.execute(request, requestOptions).let { response ->
response
.use { apiStatusHandler.handle(it) }
.apply {
if (requestOptions.responseValidation ?: clientOptions.responseValidation) {
validate()
}
val response = clientOptions.httpClient.execute(request, requestOptions)
return response
.use { apiStatusHandler.handle(it) }
.also {
if (requestOptions.responseValidation ?: clientOptions.responseValidation) {
it.validate()
}
}
}
}

override fun close() = clientOptions.httpClient.close()
Expand Down
Loading