Improve error handling for Echo backend error format
- Update ErrorResponse model to make detail and statusCode optional since
backend now returns simple {"error": "message"} format
- Update AuthApi to parse actual backend error messages instead of generic
"Registration failed"/"Login failed" strings
- Update ErrorParser to prioritize the "error" field and add fallback for
simple error map responses
- Update iOS ViewModels (Login, Register, AppleSignIn) to properly handle
400 and 409 status codes by displaying backend error messages
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,10 +3,15 @@ package com.example.casera.models
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* Error response model that handles the backend's error format.
|
||||
* The backend returns: {"error": "message"}
|
||||
* All fields except 'error' are optional for backwards compatibility.
|
||||
*/
|
||||
@Serializable
|
||||
data class ErrorResponse(
|
||||
val error: String,
|
||||
val detail: String,
|
||||
@SerialName("status_code") val statusCode: Int,
|
||||
val detail: String? = null,
|
||||
@SerialName("status_code") val statusCode: Int? = null,
|
||||
val errors: Map<String, List<String>>? = null
|
||||
)
|
||||
|
||||
@@ -19,7 +19,9 @@ class AuthApi(private val client: HttpClient = ApiClient.httpClient) {
|
||||
if (response.status.isSuccess()) {
|
||||
ApiResult.Success(response.body())
|
||||
} else {
|
||||
ApiResult.Error("Registration failed", response.status.value)
|
||||
// Parse actual error message from backend
|
||||
val errorMessage = ErrorParser.parseError(response)
|
||||
ApiResult.Error(errorMessage, response.status.value)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
ApiResult.Error(e.message ?: "Unknown error occurred")
|
||||
@@ -36,7 +38,9 @@ class AuthApi(private val client: HttpClient = ApiClient.httpClient) {
|
||||
if (response.status.isSuccess()) {
|
||||
ApiResult.Success(response.body())
|
||||
} else {
|
||||
ApiResult.Error("Login failed", response.status.value)
|
||||
// Parse actual error message from backend
|
||||
val errorMessage = ErrorParser.parseError(response)
|
||||
ApiResult.Error(errorMessage, response.status.value)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
ApiResult.Error(e.message ?: "Unknown error occurred")
|
||||
|
||||
@@ -11,13 +11,27 @@ object ErrorParser {
|
||||
isLenient = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses error response from the backend.
|
||||
* The backend returns: {"error": "message"}
|
||||
* Falls back to detail field or field-specific errors if present.
|
||||
*/
|
||||
suspend fun parseError(response: HttpResponse): String {
|
||||
return try {
|
||||
val errorResponse = response.body<ErrorResponse>()
|
||||
|
||||
// Build detailed error message
|
||||
val message = StringBuilder()
|
||||
message.append(errorResponse.detail)
|
||||
|
||||
// Primary: use the error field (main error message from backend)
|
||||
message.append(errorResponse.error)
|
||||
|
||||
// Secondary: append detail if present and different from error
|
||||
errorResponse.detail?.let { detail ->
|
||||
if (detail.isNotBlank() && detail != errorResponse.error) {
|
||||
message.append(": $detail")
|
||||
}
|
||||
}
|
||||
|
||||
// Add field-specific errors if present
|
||||
errorResponse.errors?.let { fieldErrors ->
|
||||
@@ -31,11 +45,18 @@ object ErrorParser {
|
||||
|
||||
message.toString()
|
||||
} catch (e: Exception) {
|
||||
// Fallback to reading as plain text
|
||||
// Fallback: try to parse as simple {"error": "message"} map
|
||||
try {
|
||||
response.body<String>()
|
||||
} catch (e: Exception) {
|
||||
"An error occurred (${response.status.value})"
|
||||
val simpleError = response.body<Map<String, String>>()
|
||||
simpleError["error"] ?: simpleError["message"] ?: simpleError["detail"]
|
||||
?: "An error occurred (${response.status.value})"
|
||||
} catch (e2: Exception) {
|
||||
// Last resort: read as plain text
|
||||
try {
|
||||
response.body<String>()
|
||||
} catch (e3: Exception) {
|
||||
"An error occurred (${response.status.value})"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user