Skip to content

Commit 9fe553a

Browse files
committed
feat: FaultException
mmrpc-core: - added FaultException mmrpc-server: - added ApplicationCall.respond(FaultException, ...) mmrpc-client: - modified HttpClient.exec(...) to throw FaultException when encountered
1 parent 8774fd9 commit 9fe553a

3 files changed

Lines changed: 75 additions & 19 deletions

File tree

mmrpc-client-kotlin/src/commonMain/kotlin/ktor_exec.kt

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ package org.cufy.mmrpc.client
22

33
import io.ktor.client.*
44
import io.ktor.client.call.*
5+
import io.ktor.client.plugins.*
56
import io.ktor.client.request.*
67
import io.ktor.http.*
8+
import io.ktor.http.HttpMethod
9+
import kotlinx.serialization.json.JsonObject
10+
import org.cufy.json.asContentStringOrNull
711
import org.cufy.json.serializeToJsonString
8-
import org.cufy.mmrpc.Http
9-
import org.cufy.mmrpc.HttpEndpointInfo
10-
import org.cufy.mmrpc.RoutineObject
11-
import org.cufy.mmrpc.StructObject
12+
import org.cufy.mmrpc.*
1213

1314
suspend inline fun <reified I : StructObject, reified O : StructObject> HttpClient.exec(
1415
routine: RoutineObject<I, O>,
@@ -29,18 +30,37 @@ suspend inline fun <reified I : StructObject, reified O : StructObject> HttpClie
2930
val valueString = input.serializeToJsonString()
3031
val method = endpoint.method.firstOrNull() ?: Http.POST
3132

32-
return post {
33-
baseurl?.let { this.url.takeFrom(it) }
33+
try {
34+
return post {
35+
baseurl?.let { this.url.takeFrom(it) }
3436

35-
this.method = HttpMethod.parse(method.name)
36-
this.url.appendPathSegments(endpoint.path.value)
37+
this.method = HttpMethod.parse(method.name)
38+
this.url.appendPathSegments(endpoint.path.value)
3739

38-
keyString?.let { this.headers["X-MMRPC-KEY"] = it }
39-
token?.let { bearerAuth(it) }
40+
keyString?.let { this.headers["X-MMRPC-KEY"] = it }
41+
token?.let { bearerAuth(it) }
4042

41-
contentType(ContentType.Application.Json)
42-
setBody(valueString)
43+
contentType(ContentType.Application.Json)
44+
setBody(valueString)
4345

44-
block()
45-
}.body()
46+
block()
47+
}.body()
48+
} catch (cause: ResponseException) {
49+
if (cause.response.status.value in 400..<600) {
50+
val obj = try {
51+
cause.response.body<JsonObject>()
52+
} catch (_: Exception) {
53+
throw cause
54+
}
55+
56+
val canonicalNameString = obj["type"]?.asContentStringOrNull
57+
val message = obj["message"]?.asContentStringOrNull
58+
59+
canonicalNameString ?: throw cause
60+
61+
throw FaultException(CanonicalName(canonicalNameString), message, cause)
62+
}
63+
64+
throw cause
65+
}
4666
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.cufy.mmrpc
2+
3+
open class FaultException : Exception {
4+
val canonicalName: CanonicalName
5+
6+
constructor(canonicalName: CanonicalName) : super() {
7+
this.canonicalName = canonicalName
8+
}
9+
10+
constructor(canonicalName: CanonicalName, message: String?) : super(message) {
11+
this.canonicalName = canonicalName
12+
}
13+
14+
constructor(canonicalName: CanonicalName, message: String?, cause: Throwable?) : super(message, cause) {
15+
this.canonicalName = canonicalName
16+
}
17+
18+
constructor(canonicalName: CanonicalName, cause: Throwable?) : super(cause) {
19+
this.canonicalName = canonicalName
20+
}
21+
}

mmrpc-server-kotlin/src/jvmMain/kotlin/ktor_respond.kt

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@ import io.ktor.server.application.*
55
import io.ktor.server.response.*
66
import org.cufy.json.JsonObject
77
import org.cufy.json.set
8-
import org.cufy.mmrpc.FaultInfo
9-
import org.cufy.mmrpc.FaultObject
10-
import org.cufy.mmrpc.RoutineObject
11-
import org.cufy.mmrpc.StructObject
8+
import org.cufy.mmrpc.*
129

1310
suspend inline fun <reified O : StructObject> ApplicationCall.respond(
1411
routine: RoutineObject<*, O>,
@@ -18,12 +15,30 @@ suspend inline fun <reified O : StructObject> ApplicationCall.respond(
1815
respond(status, output)
1916
}
2017

18+
suspend inline fun ApplicationCall.respond(
19+
fault: FaultException,
20+
message: String? = fault.message,
21+
status: HttpStatusCode = HttpStatusCode.BadRequest,
22+
) {
23+
val json = JsonObject {
24+
this["type"] = fault.canonicalName.value
25+
this["message"] = message
26+
}
27+
28+
respond(status, json)
29+
}
30+
2131
suspend inline fun ApplicationCall.respond(
2232
fault: FaultObject,
2333
message: String? = null,
2434
status: HttpStatusCode = HttpStatusCode.BadRequest,
2535
) {
26-
respond(fault.__info__, message, status)
36+
val json = JsonObject {
37+
this["type"] = fault.__info__.canonicalName.value
38+
this["message"] = message
39+
}
40+
41+
respond(status, json)
2742
}
2843

2944
suspend inline fun ApplicationCall.respond(

0 commit comments

Comments
 (0)