Hi, thanks for great library.
I have a question about handling 400 response.
I am developing an Android application on Kotlin and use rx_responseString() method to get a JSON from a Web API.
Api responses a JSON like bellow.
{
"firstName": "hoge"
"lastName" : "foo"
}
Data class for response.
data class User(val firstName: String, val lastName: String)
I want to get a User object from a api's response with GSON.
// In a data access class
fun getUser(): Single<User> {
// send a get request and convert response
return "http://XXX/user".httpGet().rx_responseString()
map {
p ->
val gson = Gson()
gson.fromJson(p.second.get(), User::class.java)
}
}
In an activity, I retrieve s result and display.
When response status code is 4XX, I want to display error dialog with message.
// In an Activity
getUser().subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
// onSuccess
res ->
// display json to an Activity
},
{
// onError
e ->
// check http status code
when (httpStatusCode) {
400 -> {
// show dialog with message
}
404 -> {
// show dialog with message
}
}
)
I want to know best practices to handle response with status code 4XX.
you can check statusCode in res object
getUser().subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ res ->
val statusCode = res.first.statusCode
when (statusCode) {
400 -> { }
401 -> { }
}
}, { e -> })
hope this answer your question :)
I checked that valid HTTP status code is 200 to 299 so 4XX will go to error case. Currently we cannot retrieve status code in error object yet.
@kittinunf Can we override HTTP status code validation?
Yes,
how about this;
val manager = FuelManager()
manager.addResponseInterceptor(validatorResponseInterceptor(400..419))
manager.request(Method.GET, "/status/$preDefinedStatusCode").response { req, res, result ->
request = req
response = res
when (result) {
is Result.Failure -> {
}
is Result.Success -> {
//it will be validated as Success according to the interceptor.
}
}
}
Looks nice. I will try it :D. Thank you so much.
Thank you for replying! And let me ask you one more thins.
Api returns error information JSON as below when an error occur.
{
"errorCode": "parameterError",
"message": "validation failed"
}
I want to convert this json to a kotlin object.
How should I return an error object from getUser() method?
getUser().subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ res ->
val statusCode = res.first.statusCode
when (statusCode) {
400 -> {
// handle error object which contains error JSON
}
401 -> { }
}
}, { e -> })
I assume that you have User class and Error class for success and failure cases.
You might need to deserialize JSON in subscribe instead of getUser().
You could do like this
fun getUser(): Single<User> {
return "http://XXX/user".httpGet().rx_responseString()
}
getUser().subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ res ->
val statusCode = res.first.statusCode
when (statusCode) {
200 -> Gson().fromJson(res.second.get(), User::class.java)
in 400..419 -> Gson().fromJson(res.second.get(), Error::class.java)
else -> { }
}
}, { e -> })
Thank you for replying!
If I apply clean architecture like https://blog.uptech.team/clean-architecture-in-android-with-kotlin-rxjava-dagger-2-2fdc7441edfc,
I guess it's better to keep the return type of getUser method Single
How is this?
// error object
data class ApiError(val errorCode: String, val message: String)
```kotlin
// the field contains an Api Error object.
class ApiException(val apiError: QiitaError) : Exception()
```kotlin
fun getUser(): Single<User> {
return url.httpGet().rx_responseString().flatMap { p ->
when (p.first.httpStatusCode) {
200 -> {
val gson = Gson()
Single.create<User> { e ->
e.onSuccess(gson.fromJson(p.second.get(), User::class.java))
}
}
400..419 -> {
// handle an 4XX error
val input = InputStreamReader(ByteArrayInputStream(p.first.data))
val gson = Gson()
val error = gson.fromJson(input, ApiError::class.java)
Single.error(QiitaException(error))
}
else -> {}
}
}
Looks nice. 馃槃
Most helpful comment
Thank you for replying! and tried to return an error object in an exception as below.
If I apply clean architecture like https://blog.uptech.team/clean-architecture-in-android-with-kotlin-rxjava-dagger-2-2fdc7441edfc,
I guess it's better to keep the return type of getUser method Single
How is this?
```kotlin
// the field contains an Api Error object.
class ApiException(val apiError: QiitaError) : Exception()