Skip to content

Commit 33130fd

Browse files
chore(client)!: refactor exception structure and methods (#336)
# 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 22a4cb9 commit 33130fd

File tree

62 files changed

+1025
-333
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1025
-333
lines changed
Lines changed: 58 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,87 @@
1+
// File generated from our OpenAPI spec by Stainless.
2+
13
@file:JvmName("ErrorHandler")
24

35
package com.openai.core.handlers
46

7+
import com.fasterxml.jackson.databind.JsonNode
58
import com.fasterxml.jackson.databind.json.JsonMapper
6-
import com.openai.core.http.Headers
9+
import com.fasterxml.jackson.module.kotlin.jacksonTypeRef
710
import com.openai.core.http.HttpResponse
811
import com.openai.core.http.HttpResponse.Handler
912
import com.openai.errors.BadRequestException
1013
import com.openai.errors.InternalServerException
1114
import com.openai.errors.NotFoundException
12-
import com.openai.errors.OpenAIError
1315
import com.openai.errors.PermissionDeniedException
1416
import com.openai.errors.RateLimitException
1517
import com.openai.errors.UnauthorizedException
1618
import com.openai.errors.UnexpectedStatusCodeException
1719
import com.openai.errors.UnprocessableEntityException
18-
import java.io.ByteArrayInputStream
19-
import java.io.InputStream
20+
import com.openai.models.ErrorObject
2021

2122
@JvmSynthetic
22-
internal fun errorHandler(jsonMapper: JsonMapper): Handler<OpenAIError> {
23-
val handler = jsonHandler<OpenAIError>(jsonMapper)
23+
internal fun errorHandler(jsonMapper: JsonMapper): Handler<ErrorObject?> {
24+
val handler = jsonHandler<JsonNode>(jsonMapper)
2425

25-
return object : Handler<OpenAIError> {
26-
override fun handle(response: HttpResponse): OpenAIError =
26+
return object : Handler<ErrorObject?> {
27+
override fun handle(response: HttpResponse): ErrorObject? =
2728
try {
28-
handler.handle(response)
29+
handler.handle(response).get("error")?.let {
30+
jsonMapper.readerFor(jacksonTypeRef<ErrorObject>()).readValue(it)
31+
}
2932
} catch (e: Exception) {
30-
OpenAIError.builder().build()
33+
null
3134
}
3235
}
3336
}
3437

3538
@JvmSynthetic
36-
internal fun <T> Handler<T>.withErrorHandler(errorHandler: Handler<OpenAIError>): Handler<T> =
39+
internal fun <T> Handler<T>.withErrorHandler(errorHandler: Handler<ErrorObject?>): Handler<T> =
3740
object : Handler<T> {
38-
override fun handle(response: HttpResponse): T {
41+
override fun handle(response: HttpResponse): T =
3942
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-
}
43+
in 200..299 -> this@withErrorHandler.handle(response)
44+
400 ->
45+
throw BadRequestException.builder()
46+
.headers(response.headers())
47+
.error(errorHandler.handle(response))
48+
.build()
49+
401 ->
50+
throw UnauthorizedException.builder()
51+
.headers(response.headers())
52+
.error(errorHandler.handle(response))
53+
.build()
54+
403 ->
55+
throw PermissionDeniedException.builder()
56+
.headers(response.headers())
57+
.error(errorHandler.handle(response))
58+
.build()
59+
404 ->
60+
throw NotFoundException.builder()
61+
.headers(response.headers())
62+
.error(errorHandler.handle(response))
63+
.build()
64+
422 ->
65+
throw UnprocessableEntityException.builder()
66+
.headers(response.headers())
67+
.error(errorHandler.handle(response))
68+
.build()
69+
429 ->
70+
throw RateLimitException.builder()
71+
.headers(response.headers())
72+
.error(errorHandler.handle(response))
73+
.build()
74+
in 500..599 ->
75+
throw InternalServerException.builder()
76+
.statusCode(statusCode)
77+
.headers(response.headers())
78+
.error(errorHandler.handle(response))
79+
.build()
80+
else ->
81+
throw UnexpectedStatusCodeException.builder()
82+
.statusCode(statusCode)
83+
.headers(response.headers())
84+
.error(errorHandler.handle(response))
85+
.build()
10986
}
110-
}
11187
}
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()
124-
}
125-
}
Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,93 @@
1+
// File generated from our OpenAPI spec by Stainless.
2+
13
package com.openai.errors
24

5+
import com.openai.core.JsonMissing
6+
import com.openai.core.JsonValue
7+
import com.openai.core.checkRequired
38
import com.openai.core.http.Headers
9+
import com.openai.core.jsonMapper
10+
import com.openai.models.ErrorObject
11+
import java.util.Optional
12+
import kotlin.jvm.optionals.getOrNull
13+
14+
class BadRequestException
15+
private constructor(
16+
private val headers: Headers,
17+
private val error: ErrorObject?,
18+
cause: Throwable?,
19+
) : OpenAIServiceException("400: ${error?.message()}", cause) {
20+
21+
override fun headers(): Headers = headers
22+
23+
override fun statusCode(): Int = 400
24+
25+
override fun body(): JsonValue =
26+
error?.let { JsonValue.fromJsonNode(jsonMapper().valueToTree(it)) } ?: JsonMissing.of()
27+
28+
override fun code(): Optional<String> = Optional.ofNullable(error?.code()?.getOrNull())
29+
30+
override fun param(): Optional<String> = Optional.ofNullable(error?.param()?.getOrNull())
31+
32+
override fun type(): Optional<String> = Optional.ofNullable(error?.type())
33+
34+
fun toBuilder() = Builder().from(this)
35+
36+
companion object {
37+
38+
/**
39+
* Returns a mutable builder for constructing an instance of [BadRequestException].
40+
*
41+
* The following fields are required:
42+
* ```java
43+
* .headers()
44+
* .error()
45+
* ```
46+
*/
47+
@JvmStatic fun builder() = Builder()
48+
}
49+
50+
/** A builder for [BadRequestException]. */
51+
class Builder internal constructor() {
52+
53+
private var headers: Headers? = null
54+
private var error: ErrorObject? = null
55+
private var cause: Throwable? = null
56+
57+
@JvmSynthetic
58+
internal fun from(badRequestException: BadRequestException) = apply {
59+
headers = badRequestException.headers
60+
error = badRequestException.error
61+
cause = badRequestException.cause
62+
}
63+
64+
fun headers(headers: Headers) = apply { this.headers = headers }
65+
66+
fun error(error: ErrorObject?) = apply { this.error = error }
67+
68+
fun cause(cause: Throwable?) = apply { this.cause = cause }
69+
70+
/** Alias for calling [Builder.cause] with `cause.orElse(null)`. */
71+
fun cause(cause: Optional<Throwable>) = cause(cause.getOrNull())
472

5-
class BadRequestException(headers: Headers, body: String, error: OpenAIError) :
6-
OpenAIServiceException(400, headers, body, error)
73+
/**
74+
* Returns an immutable instance of [BadRequestException].
75+
*
76+
* Further updates to this [Builder] will not mutate the returned instance.
77+
*
78+
* The following fields are required:
79+
* ```java
80+
* .headers()
81+
* .error()
82+
* ```
83+
*
84+
* @throws IllegalStateException if any required field is unset.
85+
*/
86+
fun build(): BadRequestException =
87+
BadRequestException(
88+
checkRequired("headers", headers),
89+
checkRequired("error", error),
90+
cause,
91+
)
92+
}
93+
}
Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,101 @@
1+
// File generated from our OpenAPI spec by Stainless.
2+
13
package com.openai.errors
24

5+
import com.openai.core.JsonMissing
6+
import com.openai.core.JsonValue
7+
import com.openai.core.checkRequired
38
import com.openai.core.http.Headers
9+
import com.openai.core.jsonMapper
10+
import com.openai.models.ErrorObject
11+
import java.util.Optional
12+
import kotlin.jvm.optionals.getOrNull
13+
14+
class InternalServerException
15+
private constructor(
16+
private val statusCode: Int,
17+
private val headers: Headers,
18+
private val error: ErrorObject?,
19+
cause: Throwable?,
20+
) : OpenAIServiceException("$statusCode: ${error?.message()}", cause) {
21+
22+
override fun statusCode(): Int = statusCode
23+
24+
override fun headers(): Headers = headers
25+
26+
override fun body(): JsonValue =
27+
error?.let { JsonValue.fromJsonNode(jsonMapper().valueToTree(it)) } ?: JsonMissing.of()
28+
29+
override fun code(): Optional<String> = Optional.ofNullable(error?.code()?.getOrNull())
30+
31+
override fun param(): Optional<String> = Optional.ofNullable(error?.param()?.getOrNull())
32+
33+
override fun type(): Optional<String> = Optional.ofNullable(error?.type())
34+
35+
fun toBuilder() = Builder().from(this)
36+
37+
companion object {
38+
39+
/**
40+
* Returns a mutable builder for constructing an instance of [InternalServerException].
41+
*
42+
* The following fields are required:
43+
* ```java
44+
* .statusCode()
45+
* .headers()
46+
* .error()
47+
* ```
48+
*/
49+
@JvmStatic fun builder() = Builder()
50+
}
51+
52+
/** A builder for [InternalServerException]. */
53+
class Builder internal constructor() {
54+
55+
private var statusCode: Int? = null
56+
private var headers: Headers? = null
57+
private var error: ErrorObject? = null
58+
private var cause: Throwable? = null
59+
60+
@JvmSynthetic
61+
internal fun from(internalServerException: InternalServerException) = apply {
62+
statusCode = internalServerException.statusCode
63+
headers = internalServerException.headers
64+
error = internalServerException.error
65+
cause = internalServerException.cause
66+
}
67+
68+
fun statusCode(statusCode: Int) = apply { this.statusCode = statusCode }
69+
70+
fun headers(headers: Headers) = apply { this.headers = headers }
71+
72+
fun error(error: ErrorObject?) = apply { this.error = error }
73+
74+
fun cause(cause: Throwable?) = apply { this.cause = cause }
75+
76+
/** Alias for calling [Builder.cause] with `cause.orElse(null)`. */
77+
fun cause(cause: Optional<Throwable>) = cause(cause.getOrNull())
478

5-
class InternalServerException(statusCode: Int, headers: Headers, body: String, error: OpenAIError) :
6-
OpenAIServiceException(statusCode, headers, body, error)
79+
/**
80+
* Returns an immutable instance of [InternalServerException].
81+
*
82+
* Further updates to this [Builder] will not mutate the returned instance.
83+
*
84+
* The following fields are required:
85+
* ```java
86+
* .statusCode()
87+
* .headers()
88+
* .error()
89+
* ```
90+
*
91+
* @throws IllegalStateException if any required field is unset.
92+
*/
93+
fun build(): InternalServerException =
94+
InternalServerException(
95+
checkRequired("statusCode", statusCode),
96+
checkRequired("headers", headers),
97+
checkRequired("error", error),
98+
cause,
99+
)
100+
}
101+
}

0 commit comments

Comments
 (0)