Skip to content

Commit adc2898

Browse files
chore(client)!: refactor exception structure and methods (#357)
# 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 287236c commit adc2898

File tree

62 files changed

+822
-331
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

+822
-331
lines changed
Lines changed: 54 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,84 @@
1+
// File generated from our OpenAPI spec by Stainless.
2+
13
@file:JvmName("ErrorHandler")
24

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

57
import com.fasterxml.jackson.databind.json.JsonMapper
6-
import com.withorb.api.core.http.Headers
8+
import com.withorb.api.core.JsonMissing
9+
import com.withorb.api.core.JsonValue
710
import com.withorb.api.core.http.HttpResponse
811
import com.withorb.api.core.http.HttpResponse.Handler
912
import com.withorb.api.errors.BadRequestException
1013
import com.withorb.api.errors.InternalServerException
1114
import com.withorb.api.errors.NotFoundException
12-
import com.withorb.api.errors.OrbError
1315
import com.withorb.api.errors.PermissionDeniedException
1416
import com.withorb.api.errors.RateLimitException
1517
import com.withorb.api.errors.UnauthorizedException
1618
import com.withorb.api.errors.UnexpectedStatusCodeException
1719
import com.withorb.api.errors.UnprocessableEntityException
18-
import java.io.ByteArrayInputStream
19-
import java.io.InputStream
2020

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

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

3535
@JvmSynthetic
36-
internal fun <T> Handler<T>.withErrorHandler(errorHandler: Handler<OrbError>): 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.withorb.api.errors
24

5+
import com.withorb.api.core.JsonValue
6+
import com.withorb.api.core.checkRequired
37
import com.withorb.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+
OrbServiceException("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: OrbError) :
6-
OrbServiceException(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+
}
Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,91 @@
1+
// File generated from our OpenAPI spec by Stainless.
2+
13
package com.withorb.api.errors
24

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

5-
class InternalServerException(statusCode: Int, headers: Headers, body: String, error: OrbError) :
6-
OrbServiceException(statusCode, headers, body, error)
69+
/**
70+
* Returns an immutable instance of [InternalServerException].
71+
*
72+
* Further updates to this [Builder] will not mutate the returned instance.
73+
*
74+
* The following fields are required:
75+
* ```java
76+
* .statusCode()
77+
* .headers()
78+
* .body()
79+
* ```
80+
*
81+
* @throws IllegalStateException if any required field is unset.
82+
*/
83+
fun build(): InternalServerException =
84+
InternalServerException(
85+
checkRequired("statusCode", statusCode),
86+
checkRequired("headers", headers),
87+
checkRequired("body", body),
88+
cause,
89+
)
90+
}
91+
}

0 commit comments

Comments
 (0)