validate your inputs or objects with power of the kotlin typesafe builders
quick introduction
val result=email.validate("yourEmail@gmail.com")
if(result.isValid){
println("provided email is valid ,user:${result.user},host:${result.host}")
}else{
println(result.reason!!.translate())
}
or
val result=compositeRule<User>{
User::email mustBe email
User::password mustBe inRange(8..64)
}.validate(user)
if(!result.isValid){
println(result[User::email]?.translate())
println(result[User::password]?.translate())
}
put this into your gradle script
repositories {
//...
maven { url "https://jitpack.io" }
}
dependencies {
//...
//android usage
implementation 'com.github.amir1376.kotlin-validator:android:$version'
//core (jvm)
implementation 'com.github.amir1376.kotlin-validator:core:$version'
}
in your app entry point initialize validator translation
ValidatedTranslation.initDefaultAndroidAdapter(context)
//include default translations
.applyDefaultTranslations()
before any use of translation provide a TranslationAdapter here is the default adapter
ValidatedTranslation.initWithDefault()
you can validate your input by multiple rules
val result=(email or empty).validate(input)
sometimes you want to validate a model the library has support this too for example you have the following models
data class User(
val login:String,
val name:Name,
val password:String,
val confirmPassword:String,
val gender:String
)
data class Name(
val first:String,
val last:String,
)
enum class Gender{
Male,Female
}
you can validate this with this rule
//inside a suspend function
val userValidation=compositeRule<User>{
User::login mustBe (startWithEnglishCharacter and inRange(6..64))
User::name mustBe compositeRule<Name>{
Name::first mustBe notEmpty
Name::last mustBe notEmpty
}
User::password mustBe (
containsAtLeastLowerCase(1) and
containsAtLeastUpperCase(1) and
(containsAtLeastNumber(1)) and
inRange(8..64)
)
User::confirmPassword mustBe sameAs(User::password)
User::gender mustBe oneOf<Gender>()
}
//user input
val user:User/*retrieve user object*/
val result=userValidation.validate(user)
if(!result.isValid){
// you can get reason for each property
result[User::login]
}
as you can see in the above code, user password has a complex rule , but you can extract it to a variable and because these rules are stateless (they don't store any reference of input) you can safely use this combination multiple times
val strongPassword = containsAtLeastLowerCase(1) and
containsAtLeastUpperCase(1) and
(containsAtLeastNumber(1)) and
inRange(8..64)
//.... then replace
User::password mustBe strongPassword
Of course, you can create your own rules with ease here is an example
val phone get() = rule<String>{ input->
if(phonePattern.matchEntire(input)){
thenValid()
}else{
because("your provided phone number is not valid")
}
}
if your app has support of multiple language
when building your rules ,you have to provide Reason
instead of raw string
object PhoneInvalidReason:SingleReason
val phone get() = rule<String>{ input->
if(phonePattern.matchEntire(input)){
thenValid()
}else{
because(PhoneInvalidReason)
}
}
then you have to provide PhoneInvalidReason translation to the adapter
ValidatedTranslation.adapter.apply{
//declare translation here
//this is up to you that how you want to translate that message
PhoneInvalidReason::class providedBy {
"your provided phone number is not valid"
}
}
otherwise, if you are not interested on default translation approach,
then you can create your own translation by implementing ValidatedTranslationAdapter
at the moment ,we have separated android module that contains an Android translation adapter, it has some useful extensions to provide translation from string resources
Validator.android().apply{
//declare translation here
//this is up to you that how you want to translate that message
PhoneInvalidReason::class providedByResource (R.string.my_validation_phone_invalid)
}
if you use this library for android, you can use default translation provided by the android module.
currently supported languages are
- English (default)
- Persian
the validate
method is a suspend function
accordingly, rules are all suspend functions too,
so you can have suspended calls on them
and because of that, you have to call validate
only in a coroutine scope
the core artifact doesn't have any suspend calls
this aproach is choosen for support coroutines
this library is still under beta so that may have bugs
you can consider a pull request, if you see unexpected behaviors in the library or write more common plugins
otherwise, if you have suggestions or have seen something weird out there (😁), please submit an issue
- write tests
- write more plugins
- support kotlin multiplatform