Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/maif/functional-validation
A lib to validate data and stack errors
https://github.com/maif/functional-validation
functional-programming validation-library
Last synced: 3 months ago
JSON representation
A lib to validate data and stack errors
- Host: GitHub
- URL: https://github.com/maif/functional-validation
- Owner: MAIF
- License: apache-2.0
- Created: 2020-09-23T15:29:48.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2023-05-02T13:29:01.000Z (almost 2 years ago)
- Last Synced: 2024-04-16T19:39:01.173Z (10 months ago)
- Topics: functional-programming, validation-library
- Language: Java
- Homepage:
- Size: 95.7 KB
- Stars: 7
- Watchers: 7
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: readme.md
- License: LICENSE
- Code of conduct: .github/CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# Functional Validation [![ga-badge][]][ga] [![jar-badge][]][jar]
[ga]: https://github.com/MAIF/functional-validation/actions?query=workflow%3ABuild
[ga-badge]: https://github.com/MAIF/functional-validation/workflows/Build/badge.svg
[jar]: https://maven-badges.herokuapp.com/maven-central/fr.maif/functional-validation
[jar-badge]: https://maven-badges.herokuapp.com/maven-central/fr.maif/functional-validation/badge.svgThis lib provide helpers to validate bean and compose validations stacking errors.
## Imports
Jcenter hosts this library.
### Maven
```xml
fr.maif
functional-validation
1.0.0-BETA1```
### Gradle
```
implementation 'fr.maif:functional-validation:1.0.0-BETA1'
```## Combining validations
```java
public class Viking {String name;
String email;
String website;
Integer age;public Viking(String name, String email, String website, Integer age) {
this.name = name;
this.email = email;
this.website = website;
this.age = age;
}
}public class VikingValidation {
public static final String EMAIL_PATTERN = "...";
public static final String WEBSITE_URL_PATTERN = "...";@SuppressWarnings("unchecked")
public static Rule pattern(String elt, String pattern, E error) {
Pattern compiled = Pattern.compile(pattern);
if (compiled.matcher(elt).matches()) {
return Rule.valid();
} else {
return Rule.invalid(error);
}
}public static Rule validateWebsite(String elt) {
return pattern(elt, WEBSITE_URL_PATTERN, "Website invalid");
}public static Rule validateEmail(String elt) {
return pattern(elt, EMAIL_PATTERN, "Email invalid");
}private static Rule validateAge(Integer age) {
if (age > 0 && age < 130) {
return Rule.valid();
} else {
return Rule.invalid("Age should be between 0 and 130");
}
}public static Rule notNull(E elt) {
if (elt == null) {
return Rule.invalid("should not be null");
} else {
return Rule.valid();
}
}public static Rule validateViking(Viking viking) {
return notNull(viking.email).andThen(() -> validateEmail(viking.email))
.and(notNull(viking.website).andThen(() -> validateWebsite(viking.website)))
.and(validateAge(viking.age));
}// Or with combine instead of and
public static Rule validateViking2(Viking viking) {
return Rule.combine(List.of(
notNull(viking.email).andThen(() -> validateEmail(viking.email)),
notNull(viking.website).andThen(() -> validateWebsite(viking.website)),
validateAge(viking.age)
));
}
}```
And then
```java
Rule validation = VikingValidation.validateViking(new Viking(
"Ragnard",
"[email protected]",
"https://ragnard.com",
20
));System.out.println(validation.isValid()); // true
System.out.println(validation.isInvalid()); // false
System.out.println(validation.getErrors()); // empty
String foldOk = validation.fold(
errors -> "Validation failed with " + errors.mkString(", "),
() -> "Validation succeed"
);
System.out.println(foldOk);// "Validation succeed"Rule validationOnError = VikingValidation.validateViking(new Viking(
"Ragnard",
"ragnar",
"ragnard",
150
));System.out.println(validationOnError.isValid()); // false
System.out.println(validationOnError.isInvalid()); // true
System.out.println(validationOnError.getErrors()); // ["Email invalid", "Website invalid", "Age should be between 0 and 130"]
String foldKo = validationOnError.fold(
errors -> "Validation failed with " + errors.mkString(", "),
() -> "Validation succeed"
); // "Validation failed with Email invalid, Website invalid, Age should be between 0 and 130"System.out.println(foldKo); // "Validation failed with Email invalid, Website invalid, Age should be between 0 and 130"
```## Bean validation
Bean validation can be used and mix with rules
```java
public class Viking {
@NotNull
public final String name;
public final String email;
@Pattern(regexp = WEBSITE_URL_PATTERN)
public final String website;
@Min(0)
@Max(130)
public final Integer age;public Viking(String name, String email, String website, Integer age) {
this.name = name;
this.email = email;
this.website = website;
this.age = age;
}
}```
and then
```java
Rule> validate = Rule.validate(new Viking(
"Ragnard",
"ragnar",
"ragnard",
150
));Rule validationWithStringError = validate.mapError(ConstraintViolation::getMessage);
Rule and = validationWithStringError.and(otherRule);
```## Async validation
Sometime, validation is done using an external system where the call end with a future.
```java
String name = "Ragnard";Viking viking = new Viking(
name,
"ragnar",
"ragnard",
150
);
Rule> validate = Rule.validate(viking);Rule validationWithStringError = validate.mapError(ConstraintViolation::getMessage);
// First validation and second only if the first is valid
Future> rules1 = validationWithStringError.andThenF(() -> validateUserExists(viking.name));// Or with the two validations together
Future> rules2 = validationWithStringError.combineF(validateUserExists(name));// Or combining multiple rules (same as previous)
Future> rules3 = Rule.combineF(List(
Future(validationWithStringError),
validateUserExists(name)
));```