diff --git a/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/AuthImpl.kt b/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/AuthImpl.kt index 5cc579258..a18aec388 100644 --- a/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/AuthImpl.kt +++ b/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/AuthImpl.kt @@ -524,16 +524,16 @@ internal class AuthImpl( private fun checkErrorCodes(error: GoTrueErrorResponse, response: HttpResponse): RestException? { return when (error.error) { - AuthWeakPasswordException.CODE -> AuthWeakPasswordException(error.description, response.status.value, error.weakPassword?.reasons ?: emptyList()) + AuthWeakPasswordException.CODE -> AuthWeakPasswordException(error.description, response, error.weakPassword?.reasons ?: emptyList()) AuthSessionMissingException.CODE -> { authScope.launch { Auth.logger.e { "Received session not found api error. Clearing session..." } clearSession() } - AuthSessionMissingException(response.status.value) + AuthSessionMissingException(response) } else -> { - error.error?.let { AuthRestException(it, error.description, response.status.value) } + error.error?.let { AuthRestException(it, error.description, response) } } } } diff --git a/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/exception/AuthRestException.kt b/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/exception/AuthRestException.kt index f5c123a10..5ccf99fed 100644 --- a/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/exception/AuthRestException.kt +++ b/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/exception/AuthRestException.kt @@ -1,17 +1,17 @@ package io.github.jan.supabase.auth.exception import io.github.jan.supabase.exceptions.RestException +import io.ktor.client.statement.HttpResponse /** * Base class for rest exceptions thrown by the Auth API. * @property errorCode The error code of the rest exception. This should be a known [AuthErrorCode]. If it is not, use [error] instead. - * @param message The message of the rest exception. + * @param errorDescription The description of the error. */ -open class AuthRestException(errorCode: String, message: String, statusCode: Int): RestException( +open class AuthRestException(errorCode: String, val errorDescription: String, response: HttpResponse): RestException( error = errorCode, - description = "Auth API error: $errorCode", - message = message, - statusCode = statusCode + description = "$errorDescription: $errorCode", + response = response ) { /** diff --git a/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/exception/AuthSessionMissingException.kt b/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/exception/AuthSessionMissingException.kt index f5a180f10..f2df64c4e 100644 --- a/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/exception/AuthSessionMissingException.kt +++ b/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/exception/AuthSessionMissingException.kt @@ -1,12 +1,14 @@ package io.github.jan.supabase.auth.exception +import io.ktor.client.statement.HttpResponse + /** * Exception thrown when a session is not found. */ -class AuthSessionMissingException(statusCode: Int): AuthRestException( +class AuthSessionMissingException(response: HttpResponse): AuthRestException( errorCode = CODE, - statusCode = statusCode, - message = "Session not found. This can happen if the user was logged out or deleted." + response = response, + errorDescription = "Session not found. This can happen if the user was logged out or deleted." ) { internal companion object { diff --git a/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/exception/AuthWeakPasswordException.kt b/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/exception/AuthWeakPasswordException.kt index d9d1a6dc3..d1f50d339 100644 --- a/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/exception/AuthWeakPasswordException.kt +++ b/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/exception/AuthWeakPasswordException.kt @@ -1,5 +1,7 @@ package io.github.jan.supabase.auth.exception +import io.ktor.client.statement.HttpResponse + /** * Exception thrown on sign-up if the password is too weak * @param description The description of the exception. @@ -7,12 +9,12 @@ package io.github.jan.supabase.auth.exception */ class AuthWeakPasswordException( description: String, - statusCode: Int, + response: HttpResponse, val reasons: List ) : AuthRestException( CODE, description, - statusCode + response ) { internal companion object { diff --git a/Auth/src/commonTest/kotlin/AuthRestExceptionTest.kt b/Auth/src/commonTest/kotlin/AuthRestExceptionTest.kt index 39db4412b..4ebcce3bc 100644 --- a/Auth/src/commonTest/kotlin/AuthRestExceptionTest.kt +++ b/Auth/src/commonTest/kotlin/AuthRestExceptionTest.kt @@ -51,7 +51,7 @@ class AuthRestExceptionTest { } } assertEquals("error_code", exception.error) - assertEquals("error_message", exception.message) + assertEquals("error_message", exception.errorDescription) } } @@ -83,7 +83,7 @@ class AuthRestExceptionTest { } } assertEquals("weak_password", exception.error) - assertEquals("error_message", exception.message) + assertEquals("error_message", exception.errorDescription) assertEquals(listOf("reason1", "reason2"), exception.reasons) } } diff --git a/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/Postgrest.kt b/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/Postgrest.kt index 9d163e831..67435ea8b 100644 --- a/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/Postgrest.kt +++ b/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/Postgrest.kt @@ -2,18 +2,20 @@ package io.github.jan.supabase.postgrest import io.github.jan.supabase.SupabaseClient import io.github.jan.supabase.SupabaseSerializer -import io.github.jan.supabase.exceptions.RestException +import io.github.jan.supabase.exceptions.HttpRequestException import io.github.jan.supabase.logging.SupabaseLogger import io.github.jan.supabase.plugins.CustomSerializationConfig import io.github.jan.supabase.plugins.CustomSerializationPlugin import io.github.jan.supabase.plugins.MainConfig import io.github.jan.supabase.plugins.MainPlugin import io.github.jan.supabase.plugins.SupabasePluginProvider +import io.github.jan.supabase.postgrest.exception.PostgrestRestException import io.github.jan.supabase.postgrest.query.PostgrestQueryBuilder import io.github.jan.supabase.postgrest.query.PostgrestRequestBuilder import io.github.jan.supabase.postgrest.query.PostgrestUpdate import io.github.jan.supabase.postgrest.query.request.RpcRequestBuilder import io.github.jan.supabase.postgrest.result.PostgrestResult +import io.ktor.client.plugins.HttpRequestTimeoutException import kotlinx.serialization.json.JsonObject /** @@ -66,7 +68,9 @@ sealed interface Postgrest : MainPlugin, CustomSerializationPl * * @param function The name of the function * @param request Filter the result - * @throws RestException or one of its subclasses if the request failed + * @throws PostgrestRestException if receiving an error response + * @throws HttpRequestTimeoutException if the request timed out + * @throws HttpRequestException on network related issues */ suspend fun rpc( function: String, @@ -79,7 +83,9 @@ sealed interface Postgrest : MainPlugin, CustomSerializationPl * @param function The name of the function * @param parameters The parameters for the function * @param request Filter the result - * @throws RestException or one of its subclasses if the request failed + * @throws PostgrestRestException if receiving an error response + * @throws HttpRequestTimeoutException if the request timed out + * @throws HttpRequestException on network related issues */ suspend fun rpc( function: String, diff --git a/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/PostgrestImpl.kt b/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/PostgrestImpl.kt index f4e806326..0ade59c93 100644 --- a/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/PostgrestImpl.kt +++ b/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/PostgrestImpl.kt @@ -4,18 +4,14 @@ import io.github.jan.supabase.SupabaseClient import io.github.jan.supabase.annotations.SupabaseInternal import io.github.jan.supabase.auth.authenticatedSupabaseApi import io.github.jan.supabase.bodyOrNull -import io.github.jan.supabase.exceptions.BadRequestRestException -import io.github.jan.supabase.exceptions.NotFoundRestException import io.github.jan.supabase.exceptions.RestException -import io.github.jan.supabase.exceptions.UnauthorizedRestException -import io.github.jan.supabase.exceptions.UnknownRestException +import io.github.jan.supabase.postgrest.exception.PostgrestRestException import io.github.jan.supabase.postgrest.executor.RestRequestExecutor import io.github.jan.supabase.postgrest.query.PostgrestQueryBuilder import io.github.jan.supabase.postgrest.query.request.RpcRequestBuilder import io.github.jan.supabase.postgrest.request.RpcRequest import io.github.jan.supabase.postgrest.result.PostgrestResult import io.ktor.client.statement.HttpResponse -import io.ktor.http.HttpStatusCode import kotlinx.serialization.json.JsonObject internal class PostgrestImpl(override val supabaseClient: SupabaseClient, override val config: Postgrest.Config) : Postgrest { @@ -48,12 +44,7 @@ internal class PostgrestImpl(override val supabaseClient: SupabaseClient, overri override suspend fun parseErrorResponse(response: HttpResponse): RestException { val body = response.bodyOrNull() ?: PostgrestErrorResponse("Unknown error") - return when(response.status) { - HttpStatusCode.Unauthorized -> UnauthorizedRestException(body.message, response, body.details ?: body.hint) - HttpStatusCode.NotFound -> NotFoundRestException(body.message, response, body.details ?: body.hint) - HttpStatusCode.BadRequest -> BadRequestRestException(body.message, response, body.details ?: body.hint) - else -> UnknownRestException(body.message, response, body.details ?: body.hint) - } + return PostgrestRestException(body.message, body.hint, body.details, body.code, response) } override suspend fun rpc( diff --git a/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/exception/PostgrestRestException.kt b/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/exception/PostgrestRestException.kt new file mode 100644 index 000000000..3212ee3fb --- /dev/null +++ b/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/exception/PostgrestRestException.kt @@ -0,0 +1,20 @@ +package io.github.jan.supabase.postgrest.exception + +import io.github.jan.supabase.exceptions.RestException +import io.ktor.client.statement.HttpResponse + +/** + * Exception thrown when a Postgrest request fails + * @param message The error message + * @param hint A hint to the error + * @param details Additional details about the error + * @param code The error code + * @param response The response that caused the exception + */ +class PostgrestRestException( + message: String, + val hint: String?, + val details: String?, + val code: String?, + response: HttpResponse +): RestException(message, hint ?: details, response) \ No newline at end of file diff --git a/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/PostgrestQueryBuilder.kt b/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/PostgrestQueryBuilder.kt index 7b9c832ab..2b0d76624 100644 --- a/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/PostgrestQueryBuilder.kt +++ b/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/PostgrestQueryBuilder.kt @@ -4,8 +4,8 @@ package io.github.jan.supabase.postgrest.query import io.github.jan.supabase.auth.PostgrestFilterDSL import io.github.jan.supabase.encodeToJsonElement import io.github.jan.supabase.exceptions.HttpRequestException -import io.github.jan.supabase.exceptions.RestException import io.github.jan.supabase.postgrest.Postgrest +import io.github.jan.supabase.postgrest.exception.PostgrestRestException import io.github.jan.supabase.postgrest.executor.RestRequestExecutor import io.github.jan.supabase.postgrest.mapToFirstValue import io.github.jan.supabase.postgrest.query.request.InsertRequestBuilder @@ -35,7 +35,7 @@ class PostgrestQueryBuilder( * @param columns The columns to retrieve, defaults to [Columns.ALL]. You can also use [Columns.list], [Columns.type] or [Columns.raw] to specify the columns * @param request Additional configurations for the request including filters * @return PostgrestResult which is either an error, an empty JsonArray or the data you requested as an JsonArray - * @throws RestException or one of its subclasses if receiving an error response + * @throws PostgrestRestException if receiving an error response * @throws HttpRequestTimeoutException if the request timed out * @throws HttpRequestException on network related issues */ @@ -67,7 +67,7 @@ class PostgrestQueryBuilder( * * @param values The values to insert, will automatically get serialized into json. * @param request Additional configurations for the request including filters - * @throws RestException or one of its subclasses if receiving an error response + * @throws PostgrestRestException if receiving an error response * @throws HttpRequestTimeoutException if the request timed out * @throws HttpRequestException on network related issues */ @@ -107,7 +107,7 @@ class PostgrestQueryBuilder( * * @param value The value to insert, will automatically get serialized into json. * @param request Additional filtering to apply to the query - * @throws RestException or one of its subclasses if receiving an error response + * @throws PostgrestRestException if receiving an error response * @throws HttpRequestTimeoutException if the request timed out * @throws HttpRequestException on network related issues */ @@ -121,7 +121,7 @@ class PostgrestQueryBuilder( * * @param values The values to insert, will automatically get serialized into json. * @param request Additional filtering to apply to the query - * @throws RestException or one of its subclasses if receiving an error response + * @throws PostgrestRestException if receiving an error response * @throws HttpRequestTimeoutException if the request timed out * @throws HttpRequestException on network related issues */ @@ -150,7 +150,7 @@ class PostgrestQueryBuilder( * * @param value The value to insert, will automatically get serialized into json. * @param request Additional filtering to apply to the query - * @throws RestException or one of its subclasses if receiving an error response + * @throws PostgrestRestException if receiving an error response * @throws HttpRequestTimeoutException if the request timed out * @throws HttpRequestException on network related issues */ @@ -166,7 +166,7 @@ class PostgrestQueryBuilder( * * @param update Specifies the fields to update via a DSL * @param request Additional filtering to apply to the query - * @throws RestException or one of its subclasses if receiving an error response + * @throws PostgrestRestException if receiving an error response * @throws HttpRequestTimeoutException if the request timed out * @throws HttpRequestException on network related issues */ @@ -193,7 +193,7 @@ class PostgrestQueryBuilder( * * @param value The value to update, will automatically get serialized into json. * @param request Additional filtering to apply to the query - * @throws RestException or one of its subclasses if receiving an error response + * @throws PostgrestRestException if receiving an error response * @throws HttpRequestTimeoutException if the request timed out * @throws HttpRequestException on network related issues */ @@ -219,7 +219,7 @@ class PostgrestQueryBuilder( * By default, deleted rows are not returned. To return it, call `[PostgrestRequestBuilder.select]`. * * @param request Additional filtering to apply to the query - * @throws RestException or one of its subclasses if receiving an error response + * @throws PostgrestRestException if receiving an error response * @throws HttpRequestTimeoutException if the request timed out * @throws HttpRequestException on network related issues */ diff --git a/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/request/RpcRequestBuilder.kt b/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/request/RpcRequestBuilder.kt index 8d7b1fe68..5f631cf98 100644 --- a/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/request/RpcRequestBuilder.kt +++ b/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/request/RpcRequestBuilder.kt @@ -1,11 +1,12 @@ package io.github.jan.supabase.postgrest.query.request +import io.github.jan.supabase.postgrest.Postgrest import io.github.jan.supabase.postgrest.PropertyConversionMethod import io.github.jan.supabase.postgrest.RpcMethod import io.github.jan.supabase.postgrest.query.PostgrestRequestBuilder /** - * Request builder for [Postgrest.rpcRequest] + * Request builder for [Postgrest.rpc] */ class RpcRequestBuilder(defaultSchema: String, propertyConversionMethod: PropertyConversionMethod): PostgrestRequestBuilder(propertyConversionMethod) { diff --git a/Supabase/src/commonMain/kotlin/io/github/jan/supabase/exceptions/RestException.kt b/Supabase/src/commonMain/kotlin/io/github/jan/supabase/exceptions/RestException.kt index fd19316ce..d8735bc33 100644 --- a/Supabase/src/commonMain/kotlin/io/github/jan/supabase/exceptions/RestException.kt +++ b/Supabase/src/commonMain/kotlin/io/github/jan/supabase/exceptions/RestException.kt @@ -9,39 +9,42 @@ import io.ktor.client.statement.request * Plugins may extend this class to provide more specific exceptions * @param error The error returned by Supabase * @param description The error description returned by Supabase - * @param statusCode The HTTP status code of the rest exception. + * @param response The response that caused the exception * @see UnauthorizedRestException * @see BadRequestRestException * @see NotFoundRestException * @see UnknownRestException */ -open class RestException(val error: String, val description: String?, val statusCode: Int, message: String): Exception(message) { - - constructor(error: String, response: HttpResponse, message: String? = null): this(error, message, response.status.value, """ - $error${message?.let { " ($it)" } ?: ""} +open class RestException(val error: String, val description: String?, val response: HttpResponse): Exception(""" + $error${description?.let { " ($it)" } ?: ""} URL: ${response.request.url} Headers: ${response.request.headers.entries()} Http Method: ${response.request.method.value} - """.trimIndent()) +""".trimIndent()) { + + /** + * The status code of the response + */ + val statusCode = response.status.value } /** * Thrown when supabase-kt receives a response indicating an authentication error */ -class UnauthorizedRestException(error: String, response: HttpResponse, message: String? = null): RestException(error, response, message) +class UnauthorizedRestException(error: String, response: HttpResponse, message: String? = null): RestException(error, message, response) /** * Thrown when supabase-kt receives a response indicating that the request was invalid due to missing or wrong fields */ -class BadRequestRestException(error: String, response: HttpResponse, message: String? = null): RestException(error, response, message) +class BadRequestRestException(error: String, response: HttpResponse, message: String? = null): RestException(error, message, response) /** * Thrown when supabase-kt receives a response indicating that the wanted resource was not found */ -class NotFoundRestException(error: String, response: HttpResponse, message: String? = null): RestException(error, response, message) +class NotFoundRestException(error: String, response: HttpResponse, message: String? = null): RestException(error, message, response) /** * Thrown for all other response codes */ -class UnknownRestException(error: String, response: HttpResponse, message: String? = null): RestException(error, response, message) +class UnknownRestException(error: String, response: HttpResponse, message: String? = null): RestException(error, message, response)