Skip to content

Commit 124fdfc

Browse files
authored
Merge pull request #181 from IZIVIA/fix/#179-ocpi-exception-when-possible-instead-http-exception
2 parents 4758fc2 + b5600ff commit 124fdfc

File tree

2 files changed

+51
-49
lines changed

2 files changed

+51
-49
lines changed

ocpi-toolkit-2.2.1/src/main/kotlin/com/izivia/ocpi/toolkit/common/HttpResponse.kt

Lines changed: 48 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -41,27 +41,17 @@ inline fun <reified T, reified P : Partial<T>> HttpResponse.parseSearchResultIgn
4141
* information. Any error information contained in HTTP request or OCPI body gets converted into Exceptions.
4242
* @param offset
4343
*/
44-
inline fun <reified T> HttpResponse.parseSearchResult(offset: Int): SearchResult<T> {
45-
if (!status.success()) throw HttpException(status, status.name)
46-
if (body.isNullOrBlank()) throw OcpiToolkitResponseParsingException("missing obligatory body in response")
47-
48-
val list = runCatching { mapper.deserializeOcpiResponseList<T>(body) }
49-
.onFailure { e ->
50-
throw OcpiToolkitResponseParsingException("Response cannot be parsed: $body", e)
51-
}
52-
.getOrNull()
53-
?.also { it.maybeThrowOcpiException(status) }
54-
?.data ?: emptyList()
55-
56-
return list.toSearchResult(
57-
totalCount = getHeader(Header.X_TOTAL_COUNT)?.toInt()
58-
?: throw OcpiToolkitMissingRequiredResponseHeaderException(Header.X_TOTAL_COUNT),
59-
limit = getHeader(Header.X_LIMIT)?.toInt()
60-
?: throw OcpiToolkitMissingRequiredResponseHeaderException(Header.X_LIMIT),
61-
offset = offset,
62-
nextPageUrl = getHeader(Header.LINK)?.split("<")?.elementAtOrNull(1)?.split(">")?.first(),
63-
)
64-
}
44+
inline fun <reified T> HttpResponse.parseSearchResult(offset: Int): SearchResult<T> =
45+
parseOcpiResponseBodyAndHandleErrors { mapper.deserializeOcpiResponseList<T>(body) }
46+
.orEmpty()
47+
.toSearchResult(
48+
totalCount = getHeader(Header.X_TOTAL_COUNT)?.toInt()
49+
?: throw OcpiToolkitMissingRequiredResponseHeaderException(Header.X_TOTAL_COUNT),
50+
limit = getHeader(Header.X_LIMIT)?.toInt()
51+
?: throw OcpiToolkitMissingRequiredResponseHeaderException(Header.X_LIMIT),
52+
offset = offset,
53+
nextPageUrl = getHeader(Header.LINK)?.split("<")?.elementAtOrNull(1)?.split(">")?.first(),
54+
)
6555

6656
/**
6757
* Parse body of a request that should contain data, usually POST commands.
@@ -85,43 +75,52 @@ inline fun <reified T> HttpResponse.parseOptionalResult(): T? {
8575
return parseResultOrNull()
8676
}
8777

88-
inline fun <reified T> HttpResponse.parseResultListOrNull(): List<T>? {
89-
if (!status.success()) throw HttpException(status, status.name)
90-
if (body.isNullOrBlank()) throw OcpiToolkitResponseParsingException("missing obligatory body in response")
78+
inline fun <reified T> HttpResponse.parseResultListOrNull(): List<T>? =
79+
parseOcpiResponseBodyAndHandleErrors { mapper.deserializeOcpiResponseList<T>(body) }
9180

92-
return runCatching { mapper.deserializeOcpiResponseList<T>(body) }
93-
.onFailure { e ->
94-
throw OcpiToolkitResponseParsingException("Response cannot be parsed: $body", e)
95-
}
96-
.getOrNull()
97-
?.also { it.maybeThrowOcpiException(status) }
98-
?.data
99-
}
81+
inline fun <reified T> HttpResponse.parseResultOrNull(): T? =
82+
parseOcpiResponseBodyAndHandleErrors { mapper.deserializeOcpiResponse<T>(it) }
10083

10184
/**
10285
* Parse body of a request that might contain data, like PUT/PATCH calls.
10386
* Any error information contained in HTTP request or OcpiResponseBody gets converted into Exceptions.
10487
*/
105-
inline fun <reified T> HttpResponse.parseResultOrNull(): T? {
106-
if (!status.success()) throw HttpException(status, status.name)
107-
if (body.isNullOrBlank()) throw OcpiToolkitResponseParsingException("missing obligatory body in response")
88+
inline fun <reified T> HttpResponse.parseOcpiResponseBodyAndHandleErrors(
89+
deserializeFn: (String?) -> OcpiResponseBody<T>,
90+
): T? {
91+
if (!status.success()) {
92+
// We know there was an error, so an exception must be thrown, we will try to throw an OcpiException if the
93+
// error is formatted as an OCPI error
94+
runCatching { deserializeFn(body) }
95+
.getOrElse {
96+
// If deserialization fails, it means that the response is probably not an OCPI error (if it is, it is
97+
// incorrectly formatted, so we read it as a regular HttpException)
98+
throw HttpException(status, status.name)
99+
}
100+
.throwOcpiException(status)
101+
}
108102

109-
return runCatching { mapper.deserializeOcpiResponse<T>(body) }
110-
.onFailure { e ->
103+
// We know the message is a success, so it must be formatted as an OCPI response, so we can safely throw an
104+
// exception if it is not the case
105+
return runCatching { deserializeFn(body) }
106+
.getOrElse { e ->
111107
throw OcpiToolkitResponseParsingException("Response cannot be parsed: $body", e)
112108
}
113-
.getOrNull()
114-
?.also { it.maybeThrowOcpiException(status) }
115-
?.data
109+
.also { parsedOcpiResponse ->
110+
// who knows, maybe the partner responded with 200 or 201, but the OCPI payload is an error, in that case
111+
// throw the error
112+
if (!parsedOcpiResponse.statusCode.toOcpiStatus().isSuccess()) {
113+
parsedOcpiResponse.throwOcpiException(status)
114+
}
115+
}
116+
.data
116117
}
117118

118-
inline fun <reified T> OcpiResponseBody<T>.maybeThrowOcpiException(httpStatus: HttpStatus = HttpStatus.OK) {
119-
if (statusCode != OcpiStatus.SUCCESS.code) {
120-
throw OcpiException(
121-
httpStatus = httpStatus,
122-
ocpiStatus = statusCode.toOcpiStatus(),
123-
ocpiStatusCode = statusCode,
124-
message = statusMessage ?: "",
125-
)
126-
}
119+
inline fun <reified T> OcpiResponseBody<T>.throwOcpiException(httpStatus: HttpStatus) {
120+
throw OcpiException(
121+
httpStatus = httpStatus,
122+
ocpiStatus = statusCode.toOcpiStatus(),
123+
ocpiStatusCode = statusCode,
124+
message = statusMessage.orEmpty(),
125+
)
127126
}

ocpi-toolkit-2.2.1/src/main/kotlin/com/izivia/ocpi/toolkit/common/OcpiStatus.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ enum class OcpiStatus(val code: Int) {
8585
* Used when status code in response is unknown, most likely a custom code
8686
*/
8787
UNKNOWN(9999),
88+
;
89+
90+
fun isSuccess(): Boolean = code in 1000..1999
8891
}
8992

9093
fun Int.toOcpiStatus(): OcpiStatus = OcpiStatus.values().firstOrNull { it.code == this } ?: OcpiStatus.UNKNOWN

0 commit comments

Comments
 (0)