Sealed class de resposta para o crud.
sealed class Resource<T> {
data class Error<T>(
val status: HttpStatusCode = HttpStatusCode.Conflict, val data: T? = null
) : Resource<T>()
data class NotImplemented<T>(
val status: HttpStatusCode = HttpStatusCode.NotImplemented, val data: T? = null
) : Resource<T>()
data class Success<T>(
val status: HttpStatusCode = HttpStatusCode.OK, val data: T? = null
) : Resource<T>()
val isImplemented: Boolean
get() = this !is NotImplemented
val isSuccess: Boolean
get() = this is Success
val dataValue: T?
get() = when (this) {
is Success -> data as T?
is Error -> data as T?
is NotImplemented -> null
}
val statusCode: HttpStatusCode
get() = when (this) {
is Success -> status
is Error -> status
is NotImplemented -> HttpStatusCode.NotImplemented
}
}
Crud para o ktor.
class InvalidRequest(message: InvalidRequestType) : Exception(message.name)
enum class InvalidRequestType { AUTH, DATA }
suspend fun ApplicationCall.throwException(type: InvalidRequestType): Nothing = kotlin.run {
this.respond(if (type == InvalidRequestType.AUTH) HttpStatusCode.Unauthorized else HttpStatusCode.BadRequest)
throw InvalidRequest(type)
}
suspend inline fun <reified R> ApplicationCall.responseRequest(resource: Resource<R>) =
this.respond(resource.statusCode, resource.dataValue ?: "")
suspend inline fun <reified T, reified R> ApplicationCall.receiveObject(
useCase: (T) -> Resource<R>
) = responseRequest(useCase(this.receiveNullable<T>() ?: throwException(InvalidRequestType.DATA)))
suspend inline fun <reified R> ApplicationCall.receiveParameter(
name: String,
useCase: (String) -> Resource<R>
) = responseRequest(useCase(this.parameters[name] ?: throwException(InvalidRequestType.DATA)))
suspend inline fun <reified R> ApplicationCall.receiveGetAll(
useCase: () -> Resource<List<R>>
) = responseRequest(useCase())
suspend fun ApplicationCall.getProfileIdFromJwt() = this.principal<JWTPrincipal>()?.get(Constants.PROFILE_ID)
?: throwException(InvalidRequestType.AUTH)
suspend fun ApplicationCall.getSignIdFromJwt() = this.principal<JWTPrincipal>()?.get(Constants.SIGN_ID)
?: throwException(InvalidRequestType.AUTH)
inline fun <reified T, reified R> Route.crud(
crossinline add: suspend (userId: String, data: T) -> Resource<R>,
crossinline delete: suspend (userId: String, data: T) -> Resource<R>,
crossinline getAll: suspend (userId: String) -> Resource<List<R>>,
crossinline getById: suspend (userId: String, data: String) -> Resource<R>,
crossinline update: suspend (signId: String, profileId: String, data: T) -> Resource<R>
) {
post(Routes.Crud.Add.route) { call.receiveObject<T, R> { add(call.getProfileIdFromJwt(), it) } }
delete(Routes.Crud.Delete.route) { call.receiveObject<T, R> { delete(call.getProfileIdFromJwt(), it) } }
get(Routes.Crud.GetAll.route) { call.receiveGetAll { getAll(call.getProfileIdFromJwt()) } }
get(Routes.Crud.GetById.route + "/{$\{Constants.SIGN_ID}}") {
call.receiveParameter<R>(Constants.SIGN_ID) { getById(call.getProfileIdFromJwt(), it) }
}
put(Routes.Crud.Update.route) {
call.receiveObject<T, R> {
update(
call.getSignIdFromJwt(),
call.getProfileIdFromJwt(),
it
)
}
}
}