Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/konform-kt/konform
Portable validations for Kotlin
https://github.com/konform-kt/konform
kotlin kotlin-multiplatform validation
Last synced: 3 months ago
JSON representation
Portable validations for Kotlin
- Host: GitHub
- URL: https://github.com/konform-kt/konform
- Owner: konform-kt
- License: mit
- Created: 2018-03-07T20:32:19.000Z (almost 7 years ago)
- Default Branch: main
- Last Pushed: 2024-05-22T09:39:14.000Z (8 months ago)
- Last Synced: 2024-05-22T10:54:21.266Z (8 months ago)
- Topics: kotlin, kotlin-multiplatform, validation
- Language: Kotlin
- Homepage: https://www.konform.io
- Size: 421 KB
- Stars: 618
- Watchers: 8
- Forks: 39
- Open Issues: 21
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Codeowners: .github/CODEOWNERS
Awesome Lists containing this project
- awesome-kotlin-multiplatform - konform - Portable validations. (Libraries / Test)
- awesome-kotlin - Konform - Konform is a type-safe, multiplatform kotlin object validator with fluent dsl. (Libraries)
- awesome-kotlin-multiplatform - Konform - Portable validations for Kotlin. (Testing / SQL)
README
[![Test](https://github.com/konform-kt/konform/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/konform-kt/konform/actions/workflows/gradle.yml)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.konform/konform/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.konform/konform)# Portable validations for Kotlin
- **✅ Type-safe DSL**
- **🔗 Multi-platform support** (JVM, JS, Native, Wasm)
- **🐥 Zero dependencies**### Installation
For multiplatform projects:
```
kotlin {
sourceSets {
commonMain {
dependencies {
implementation("io.konform:konform:0.7.0")
}
}
}
}
```For jvm-only projects add:
```
dependencies {
implementation("io.konform:konform-jvm:0.7.0")
}
```### Use
Suppose you have a data class like this:
```kotlin
data class UserProfile(
val fullName: String,
val age: Int?
)
```Using the Konform type-safe DSL you can quickly write up a validation
```kotlin
val validateUser = Validation {
UserProfile::fullName {
minLength(2)
maxLength(100)
}UserProfile::age ifPresent {
minimum(0)
maximum(150)
}
}
```and apply it to your data
```kotlin
val invalidUser = UserProfile("A", -1)
val validationResult = validateUser(invalidUser)
```since the validation fails the `validationResult` will be of type `Invalid` and you can get a list of validation errors by indexed access:
```kotlin
validationResult[UserProfile::fullName]
// yields listOf("must have at least 2 characters")validationResult[UserProfile::age]
// yields listOf("must be at least '0'")
```or you can get all validation errors with details as a list:
```kotlin
validationResult.errors
// yields listOf(
// ValidationError(dataPath=.fullName, message=must have at least 2 characters),
// ValidationError(dataPath=.age, message=must be at least '0'
// )
```In case the validation went through successfully you get a result of type `Valid` with the validated value in the `value` field.
```kotlin
val validUser = UserProfile("Alice", 25)
val validationResult = validateUser(validUser)
// yields Valid(UserProfile("Alice", 25))
```### Detailed usage
#### Hints
You can add custom hints to validations
```kotlin
val validateUser = Validation {
UserProfile::age ifPresent {
minimum(0) hint "Registering before birth is not supported"
}
}
```You can use `{value}` to include the `.toString()`-ed data in the hint
```kotlin
val validateUser = Validation {
UserProfile::fullName {
minLength(2) hint "'{value}' is too short a name, must be at least 2 characters long."
}
}
```#### Custom validations
You can add custom validations on properties by using `addConstraint`
```kotlin
val validateUser = Validation {
UserProfile::fullName {
addConstraint("Name cannot contain a tab") { !it.contains("\t") }
}
}
```You can transform data and then add a validation on the result
```kotlin
val validateUser = Validation {
validate("trimmedName", { it.fullName.trim() }) {
minLength(5)
}
// This also required and ifPresent for nullable values
required("yourName", /* ...*/) {
// your validations, giving an error out if the result is null
}
ifPresent("yourName", /* ... */) {
// your validations, only running if the result is not null
}
}
```#### Split validations
You can define validations separately and run them from other validations
```kotlin
val ageCheck = Validation {
required {
minimum(21)
}
}val validateUser = Validation {
UserProfile::age {
run(ageCheck)
}// You can also transform the data and then run a validation against the result
validate("ageMinus10", { it.age?.let { age -> age - 10 } }) {
run(ageCheck)
}
}
```#### Collections
It is also possible to validate nested data classes and properties that are collections (List, Map, etc...)
```kotlin
data class Person(val name: String, val email: String?, val age: Int)data class Event(
val organizer: Person,
val attendees: List,
val ticketPrices: Map
)val validateEvent = Validation {
Event::organizer {
// even though the email is nullable you can force it to be set in the validation
Person::email required {
pattern("[email protected]") hint "Organizers must have a BigCorp email address"
}
}// validation on the attendees list
Event::attendees {
maxItems(100)
}// validation on individual attendees
Event::attendees onEach {
Person::name {
minLength(2)
}
Person::age {
minimum(18) hint "Attendees must be 18 years or older"
}
// Email is optional but if it is set it must be valid
Person::email ifPresent {
pattern(".+@.+\..+") hint "Please provide a valid email address (optional)"
}
}// validation on the ticketPrices Map as a whole
Event::ticketPrices {
minItems(1) hint "Provide at least one ticket price"
}// validations for the individual entries
Event::ticketPrices onEach {
// Tickets may be free in which case they are null
Entry::value ifPresent {
minimum(0.01)
}
}
}
```Errors in the `ValidationResult` can also be accessed using the index access method. In case of `Iterables` and `Arrays` you use the
numerical index and in case of `Maps` you use the key as string.```kotlin
// get the error messages for the first attendees age if any
result[Event::attendees, 0, Person::age]// get the error messages for the free ticket if any
result[Event::ticketPrices, "free"]
```### Other validation libraries written in Kotlin
- Valikator: https://github.com/valiktor/valiktor
- Kalidation: https://github.com/rcapraro/kalidation### Integration with testing libraries
- [Kotest](https://kotest.io) provides various matchers for use with Konform. They can be used in your tests to assert that a given object
is validated successfully or fails validation with specific error messages.
See [documentation](https://kotest.io/docs/assertions/konform-matchers.html).##### Maintainer
[David Hoepelman](https://hoepelman.dev/) (Current maintainer)
[Niklas Lochschmidt](https://niklaslochschmidt.com) (Original author, co-maintainer)##### License
[MIT License](https://github.com/konform-kt/konform/blob/main/LICENSE)