-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #317 from hotwired/visit-errors
Pass more detailed visit errors to apps to avoid ambiguity
- Loading branch information
Showing
17 changed files
with
609 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
159 changes: 159 additions & 0 deletions
159
turbo/src/main/kotlin/dev/hotwire/turbo/errors/HttpError.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
package dev.hotwire.turbo.errors | ||
|
||
import android.webkit.WebResourceResponse | ||
|
||
/** | ||
* Errors representing HTTP status codes received from the server. | ||
*/ | ||
sealed interface HttpError : TurboVisitError { | ||
val statusCode: Int | ||
val reasonPhrase: String? | ||
|
||
/** | ||
* Errors representing HTTP client errors in the 400..499 range. | ||
*/ | ||
sealed interface ClientError : HttpError { | ||
data object BadRequest : ClientError { | ||
override val statusCode = 400 | ||
override val reasonPhrase = "Bad Request" | ||
} | ||
|
||
data object Unauthorized : ClientError { | ||
override val statusCode = 401 | ||
override val reasonPhrase = "Unauthorized" | ||
} | ||
|
||
data object Forbidden : ClientError { | ||
override val statusCode = 403 | ||
override val reasonPhrase = "Forbidden" | ||
} | ||
|
||
data object NotFound : ClientError { | ||
override val statusCode = 404 | ||
override val reasonPhrase = "Not Found" | ||
} | ||
|
||
data object MethodNotAllowed : ClientError { | ||
override val statusCode = 405 | ||
override val reasonPhrase = "Method Not Allowed" | ||
} | ||
|
||
data object NotAccessible : ClientError { | ||
override val statusCode = 406 | ||
override val reasonPhrase = "Not Accessible" | ||
} | ||
|
||
data object ProxyAuthenticationRequired : ClientError { | ||
override val statusCode = 407 | ||
override val reasonPhrase = "Proxy Authentication Required" | ||
} | ||
|
||
data object RequestTimeout : ClientError { | ||
override val statusCode = 408 | ||
override val reasonPhrase = "Request Timeout" | ||
} | ||
|
||
data object Conflict : ClientError { | ||
override val statusCode = 409 | ||
override val reasonPhrase = "Conflict" | ||
} | ||
|
||
data object MisdirectedRequest : ClientError { | ||
override val statusCode = 421 | ||
override val reasonPhrase = "Misdirected Request" | ||
} | ||
|
||
data object UnprocessableEntity : ClientError { | ||
override val statusCode = 422 | ||
override val reasonPhrase = "Unprocessable Entity" | ||
} | ||
|
||
data object PreconditionRequired : ClientError { | ||
override val statusCode = 428 | ||
override val reasonPhrase = "Precondition Required" | ||
} | ||
|
||
data object TooManyRequests : ClientError { | ||
override val statusCode = 429 | ||
override val reasonPhrase = "Too Many Requests" | ||
} | ||
|
||
data class Other( | ||
override val statusCode: Int, | ||
override val reasonPhrase: String? | ||
) : ClientError | ||
} | ||
|
||
/** | ||
* Errors representing HTTP server errors in the 500..599 range. | ||
*/ | ||
sealed interface ServerError : HttpError { | ||
data object InternalServerError : ServerError { | ||
override val statusCode = 500 | ||
override val reasonPhrase = "Internal Server Error" | ||
} | ||
|
||
data object NotImplemented : ServerError { | ||
override val statusCode = 501 | ||
override val reasonPhrase = "Not Implemented" | ||
} | ||
|
||
data object BadGateway : ServerError { | ||
override val statusCode = 502 | ||
override val reasonPhrase = "Bad Gateway" | ||
} | ||
|
||
data object ServiceUnavailable : ServerError { | ||
override val statusCode = 503 | ||
override val reasonPhrase = "Service Unavailable" | ||
} | ||
|
||
data object GatewayTimeout : ServerError { | ||
override val statusCode = 504 | ||
override val reasonPhrase = "Gateway Timeout" | ||
} | ||
|
||
data object HttpVersionNotSupported : ServerError { | ||
override val statusCode = 505 | ||
override val reasonPhrase = "Http Version Not Supported" | ||
} | ||
|
||
data class Other( | ||
override val statusCode: Int, | ||
override val reasonPhrase: String? | ||
) : ServerError | ||
} | ||
|
||
data class UnknownError( | ||
override val statusCode: Int, | ||
override val reasonPhrase: String? | ||
) : HttpError | ||
|
||
companion object { | ||
fun from(errorResponse: WebResourceResponse): HttpError { | ||
return getError(errorResponse.statusCode, errorResponse.reasonPhrase) | ||
} | ||
|
||
fun from(statusCode: Int): HttpError { | ||
return getError(statusCode, null) | ||
} | ||
|
||
private fun getError(statusCode: Int, reasonPhrase: String?): HttpError { | ||
if (statusCode in 400..499) { | ||
return ClientError::class.sealedSubclasses | ||
.mapNotNull { it.objectInstance } | ||
.firstOrNull { it.statusCode == statusCode } | ||
?: ClientError.Other(statusCode, reasonPhrase) | ||
} | ||
|
||
if (statusCode in 500..599) { | ||
return ServerError::class.sealedSubclasses | ||
.map { it.objectInstance } | ||
.firstOrNull { it?.statusCode == statusCode } | ||
?: ServerError.Other(statusCode, reasonPhrase) | ||
} | ||
|
||
return UnknownError(statusCode, reasonPhrase) | ||
} | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
turbo/src/main/kotlin/dev/hotwire/turbo/errors/LoadError.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package dev.hotwire.turbo.errors | ||
|
||
/** | ||
* Errors representing when turbo.js or the native adapter fails | ||
* to load on a page. | ||
*/ | ||
sealed interface LoadError : TurboVisitError { | ||
val description: String | ||
|
||
data object NotPresent : LoadError { | ||
override val description = "Turbo Not Present" | ||
} | ||
|
||
data object NotReady : LoadError { | ||
override val description = "Turbo Not Ready" | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
turbo/src/main/kotlin/dev/hotwire/turbo/errors/TurboVisitError.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package dev.hotwire.turbo.errors | ||
|
||
/** | ||
* Represents all possible errors received when attempting to load a page. | ||
*/ | ||
sealed interface TurboVisitError |
Oops, something went wrong.