Skip to content

Commit 8463834

Browse files
chore(client)!: refactor exception structure and methods (#164)
# Migration Previously you would access error JSON on an exception via `exception.error()._additionalProperties()`, which would return `Map<String, JsonValue>`. Now you would access this via `exception.body()`, which returns `JsonValue`. You should no longer assume that the returned error JSON is an object. You can check via `exception.body().asObject()`.
1 parent 140986d commit 8463834

54 files changed

Lines changed: 807 additions & 321 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 54 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1+
// File generated from our OpenAPI spec by Stainless.
2+
13
@file:JvmName("ErrorHandler")
24

35
package com.braintrustdata.api.core.handlers
46

5-
import com.braintrustdata.api.core.http.Headers
7+
import com.braintrustdata.api.core.JsonMissing
8+
import com.braintrustdata.api.core.JsonValue
69
import com.braintrustdata.api.core.http.HttpResponse
710
import com.braintrustdata.api.core.http.HttpResponse.Handler
811
import com.braintrustdata.api.errors.BadRequestException
9-
import com.braintrustdata.api.errors.BraintrustError
1012
import com.braintrustdata.api.errors.InternalServerException
1113
import com.braintrustdata.api.errors.NotFoundException
1214
import com.braintrustdata.api.errors.PermissionDeniedException
@@ -15,111 +17,68 @@ import com.braintrustdata.api.errors.UnauthorizedException
1517
import com.braintrustdata.api.errors.UnexpectedStatusCodeException
1618
import com.braintrustdata.api.errors.UnprocessableEntityException
1719
import com.fasterxml.jackson.databind.json.JsonMapper
18-
import java.io.ByteArrayInputStream
19-
import java.io.InputStream
2020

2121
@JvmSynthetic
22-
internal fun errorHandler(jsonMapper: JsonMapper): Handler<BraintrustError> {
23-
val handler = jsonHandler<BraintrustError>(jsonMapper)
22+
internal fun errorHandler(jsonMapper: JsonMapper): Handler<JsonValue> {
23+
val handler = jsonHandler<JsonValue>(jsonMapper)
2424

25-
return object : Handler<BraintrustError> {
26-
override fun handle(response: HttpResponse): BraintrustError =
25+
return object : Handler<JsonValue> {
26+
override fun handle(response: HttpResponse): JsonValue =
2727
try {
2828
handler.handle(response)
2929
} catch (e: Exception) {
30-
BraintrustError.builder().build()
30+
JsonMissing.of()
3131
}
3232
}
3333
}
3434

3535
@JvmSynthetic
36-
internal fun <T> Handler<T>.withErrorHandler(errorHandler: Handler<BraintrustError>): Handler<T> =
36+
internal fun <T> Handler<T>.withErrorHandler(errorHandler: Handler<JsonValue>): Handler<T> =
3737
object : Handler<T> {
38-
override fun handle(response: HttpResponse): T {
38+
override fun handle(response: HttpResponse): T =
3939
when (val statusCode = response.statusCode()) {
40-
in 200..299 -> {
41-
return this@withErrorHandler.handle(response)
42-
}
43-
400 -> {
44-
val buffered = response.buffered()
45-
throw BadRequestException(
46-
buffered.headers(),
47-
stringHandler().handle(buffered),
48-
errorHandler.handle(buffered),
49-
)
50-
}
51-
401 -> {
52-
val buffered = response.buffered()
53-
throw UnauthorizedException(
54-
buffered.headers(),
55-
stringHandler().handle(buffered),
56-
errorHandler.handle(buffered),
57-
)
58-
}
59-
403 -> {
60-
val buffered = response.buffered()
61-
throw PermissionDeniedException(
62-
buffered.headers(),
63-
stringHandler().handle(buffered),
64-
errorHandler.handle(buffered),
65-
)
66-
}
67-
404 -> {
68-
val buffered = response.buffered()
69-
throw NotFoundException(
70-
buffered.headers(),
71-
stringHandler().handle(buffered),
72-
errorHandler.handle(buffered),
73-
)
74-
}
75-
422 -> {
76-
val buffered = response.buffered()
77-
throw UnprocessableEntityException(
78-
buffered.headers(),
79-
stringHandler().handle(buffered),
80-
errorHandler.handle(buffered),
81-
)
82-
}
83-
429 -> {
84-
val buffered = response.buffered()
85-
throw RateLimitException(
86-
buffered.headers(),
87-
stringHandler().handle(buffered),
88-
errorHandler.handle(buffered),
89-
)
90-
}
91-
in 500..599 -> {
92-
val buffered = response.buffered()
93-
throw InternalServerException(
94-
statusCode,
95-
buffered.headers(),
96-
stringHandler().handle(buffered),
97-
errorHandler.handle(buffered),
98-
)
99-
}
100-
else -> {
101-
val buffered = response.buffered()
102-
throw UnexpectedStatusCodeException(
103-
statusCode,
104-
buffered.headers(),
105-
stringHandler().handle(buffered),
106-
errorHandler.handle(buffered),
107-
)
108-
}
40+
in 200..299 -> this@withErrorHandler.handle(response)
41+
400 ->
42+
throw BadRequestException.builder()
43+
.headers(response.headers())
44+
.body(errorHandler.handle(response))
45+
.build()
46+
401 ->
47+
throw UnauthorizedException.builder()
48+
.headers(response.headers())
49+
.body(errorHandler.handle(response))
50+
.build()
51+
403 ->
52+
throw PermissionDeniedException.builder()
53+
.headers(response.headers())
54+
.body(errorHandler.handle(response))
55+
.build()
56+
404 ->
57+
throw NotFoundException.builder()
58+
.headers(response.headers())
59+
.body(errorHandler.handle(response))
60+
.build()
61+
422 ->
62+
throw UnprocessableEntityException.builder()
63+
.headers(response.headers())
64+
.body(errorHandler.handle(response))
65+
.build()
66+
429 ->
67+
throw RateLimitException.builder()
68+
.headers(response.headers())
69+
.body(errorHandler.handle(response))
70+
.build()
71+
in 500..599 ->
72+
throw InternalServerException.builder()
73+
.statusCode(statusCode)
74+
.headers(response.headers())
75+
.body(errorHandler.handle(response))
76+
.build()
77+
else ->
78+
throw UnexpectedStatusCodeException.builder()
79+
.statusCode(statusCode)
80+
.headers(response.headers())
81+
.body(errorHandler.handle(response))
82+
.build()
10983
}
110-
}
111-
}
112-
113-
private fun HttpResponse.buffered(): HttpResponse {
114-
val body = body().readBytes()
115-
116-
return object : HttpResponse {
117-
override fun statusCode(): Int = this@buffered.statusCode()
118-
119-
override fun headers(): Headers = this@buffered.headers()
120-
121-
override fun body(): InputStream = ByteArrayInputStream(body)
122-
123-
override fun close() = this@buffered.close()
12484
}
125-
}
Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,80 @@
1+
// File generated from our OpenAPI spec by Stainless.
2+
13
package com.braintrustdata.api.errors
24

5+
import com.braintrustdata.api.core.JsonValue
6+
import com.braintrustdata.api.core.checkRequired
37
import com.braintrustdata.api.core.http.Headers
8+
import java.util.Optional
9+
import kotlin.jvm.optionals.getOrNull
10+
11+
class BadRequestException
12+
private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) :
13+
BraintrustServiceException("400: $body", cause) {
14+
15+
override fun headers(): Headers = headers
16+
17+
override fun body(): JsonValue = body
18+
19+
override fun statusCode(): Int = 400
20+
21+
fun toBuilder() = Builder().from(this)
22+
23+
companion object {
24+
25+
/**
26+
* Returns a mutable builder for constructing an instance of [BadRequestException].
27+
*
28+
* The following fields are required:
29+
* ```java
30+
* .headers()
31+
* .body()
32+
* ```
33+
*/
34+
@JvmStatic fun builder() = Builder()
35+
}
36+
37+
/** A builder for [BadRequestException]. */
38+
class Builder internal constructor() {
39+
40+
private var headers: Headers? = null
41+
private var body: JsonValue? = null
42+
private var cause: Throwable? = null
43+
44+
@JvmSynthetic
45+
internal fun from(badRequestException: BadRequestException) = apply {
46+
headers = badRequestException.headers
47+
body = badRequestException.body
48+
cause = badRequestException.cause
49+
}
50+
51+
fun headers(headers: Headers) = apply { this.headers = headers }
52+
53+
fun body(body: JsonValue) = apply { this.body = body }
54+
55+
fun cause(cause: Throwable?) = apply { this.cause = cause }
56+
57+
/** Alias for calling [Builder.cause] with `cause.orElse(null)`. */
58+
fun cause(cause: Optional<Throwable>) = cause(cause.getOrNull())
459

5-
class BadRequestException(headers: Headers, body: String, error: BraintrustError) :
6-
BraintrustServiceException(400, headers, body, error)
60+
/**
61+
* Returns an immutable instance of [BadRequestException].
62+
*
63+
* Further updates to this [Builder] will not mutate the returned instance.
64+
*
65+
* The following fields are required:
66+
* ```java
67+
* .headers()
68+
* .body()
69+
* ```
70+
*
71+
* @throws IllegalStateException if any required field is unset.
72+
*/
73+
fun build(): BadRequestException =
74+
BadRequestException(
75+
checkRequired("headers", headers),
76+
checkRequired("body", body),
77+
cause,
78+
)
79+
}
80+
}

braintrust-java-core/src/main/kotlin/com/braintrustdata/api/errors/BraintrustError.kt

Lines changed: 0 additions & 82 deletions
This file was deleted.
Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,17 @@
1+
// File generated from our OpenAPI spec by Stainless.
2+
13
package com.braintrustdata.api.errors
24

5+
import com.braintrustdata.api.core.JsonValue
36
import com.braintrustdata.api.core.http.Headers
47

58
abstract class BraintrustServiceException
6-
@JvmOverloads
7-
constructor(
8-
private val statusCode: Int,
9-
private val headers: Headers,
10-
private val body: String,
11-
private val error: BraintrustError,
12-
message: String = "$statusCode: $error",
13-
cause: Throwable? = null,
14-
) : BraintrustException(message, cause) {
15-
16-
fun statusCode(): Int = statusCode
9+
protected constructor(message: String, cause: Throwable? = null) :
10+
BraintrustException(message, cause) {
1711

18-
fun headers(): Headers = headers
12+
abstract fun statusCode(): Int
1913

20-
fun body(): String = body
14+
abstract fun headers(): Headers
2115

22-
fun error(): BraintrustError = error
16+
abstract fun body(): JsonValue
2317
}

0 commit comments

Comments
 (0)