Save 37% off PRO during our Black Friday Sale! »

Vader & the Army of Validators

Vader & the Army of Validators

A generic bean validation framework built & consumed by teams at Salesforce, to cater specific validation needs of Salesforce REST APIs. It abstracts away the validation complexity and promotes low-code config-based validation. This is built entirely using FOSS libraries and is about ripe to open-source.

5b88ad20a23d5cacecb20eb80f5f69d8?s=128

Gopal S Akshintala

October 05, 2021
Tweet

Transcript

  1. Vade r 🦾 & 🦾 The Army of Validators

  2. Why a new Framework? 🤷 @GopalAkshintala

  3. @GopalAkshintala Why a new Framework? Salesforce core has no de-facto

    standard for Bean validatio n Same Validations, Different execution strategy per contex t No easy way to share validations among Beans that share common DS
  4. @GopalAkshintala If-else-try-catch-for Example🚨

  5. @GopalAkshintala Why a new Framework? Salesforce core has no de-facto

    standard for Bean validatio n Same Validations, Different execution strategy per contex t No easy way to share validations among Beans that share common DS
  6. @GopalAkshintala class Container { Member member; } ContainerService Validation Sharing

    { “key”: “value”, “member”: { “id”: 1 } } class Member { int id; } MemberService { “id”: 1 }
  7. @GopalAkshintala The Vision

  8. @GopalAkshintala

  9. @GopalAkshintala Consumed i n Production By 3 Team s Rev

    Hydr a Rev Delphinu s Rev Centaurus In 3 different domain s Payment s Ta x Billing
  10. @GopalAkshintala 🗣 Presented @ Confs 🇺🇸 All Things Open, 2020,

    Raleigh, USA. 📹 🏴󠁧󠁢󠁥󠁮󠁧󠁿 Kotlin User Group, London 🇩🇪 Berlin Functional Programming Group 🇳🇴 JavaBin, Norway 🇩🇪 Kotlin User Group, Berlin 🇮🇳 Google Developer Group Devfest 2019 🇮🇳 Java User Group Hyderabad (@JUGHyd) 🇮🇳 Salesforce, Hyderabad, India 🇮🇳 Kotlin User Group, Hyderabad 🇪🇸 JBCN Conf, 2020, Barcelona, Spain
  11. @GopalAkshintala Enough Sales Pitching!

  12. @GopalAkshintala We're Zealous about keeping the dev-experience Simple!

  13. @GopalAkshintala API for Non-Batch & Batch

  14. @GopalAkshintala Execution Strategies

  15. @GopalAkshintala Data-Structures to Validate

  16. Vader.validateAndFailFast(…): Optional<FailureT> @GopalAkshintala

  17. Vader.validateAndAccumulateErrors(…): List<FailureT> @GopalAkshintala

  18. @GopalAkshintala

  19. @GopalAkshintala 2D Problem Beans Validations

  20. @GopalAkshintala Validation layer Service layer DB layer Aggregated Response

  21. VaderBatch.validateAndFailFastForEach(…): List<Either<FailureT, ValidatableT >> @GopalAkshintala

  22. Either Bean Validation Failure Sum-Type io.vavr.control.Either @GopalAkshintala Left Right

  23. VaderBatch.validateAndFailFastForEach(…): List<Either<Tuple2<PairT, FailureT>, ValidatableT >> @GopalAkshintala

  24. VaderBatch.validateAndFailFastForAny(…): Optional<FailureT> @GopalAkshintala

  25. VaderBatch.validateAndFailFastForAny(…): Optional<Tuple2<PairT, FailureT > > @GopalAkshintala

  26. How to write Validators? @GopalAkshintala

  27. Validator: (ValidatableT) -> FailureT static final Validator<Bean, ValidationFailure> validator =

    bean -> { if (bean == null) { return new ValidationFailure(FIELD_NULL_OR_EMPTY); } else { return ValidationFailure.NONE; } }; @GopalAkshintala
  28. @GopalAkshintala Consumer defines the FailureT FailureT class may include :

    Localised error messag e API error code s Exception handling
  29. ValidatorEtr: (Either<FailureT, ValidatableT>) -> Either<FailureT, ?> static final ValidatorEtr<Bean, ValidationFailure>

    validatorEtr = beanEtr -> beanEtr.filterOrElse( bean -> bean.id != null, badBean - > new ValidationFailure(FIELD_NULL_OR_EMPTY)); ⚠ You may need some Functional Programming experience to use this type @GopalAkshintala
  30. How to pass these Validators into the API? @GopalAkshintala

  31. @GopalAkshintala 🎛 Config for Validation

  32. @GopalAkshintala Hook Validators with Config var config = ValidationConfig.<Bean, ValidationFailure>toValidate()

    .withValidators(Tuple.of(validatorChain, ValidationFailure.NONE)) .prepare(); Validator<Bean, ValidationFailure> validator1 = bean - > NONE; Validator<Bean, ValidationFailure> validator2 = bean - > NONE; Validator<Bean, ValidationFailure> validator3 = bean - > UNKNOWN_EXCEPTION; List<Validator<Bean, ValidationFailure >> validatorChain = List.of(validator1, validator2, validator3); var result = Vader.validateAndFailFast(VALIDATABLE, validationConfig);
  33. @GopalAkshintala ValidatorEtr<Bean, ValidationFailure> validatorEtr1 = bean -> Either.right(true); ValidatorEtr<Bean, ValidationFailure>

    validatorEtr2 = bean -> bean.map(Bean :: getId).filterOrElse(id - > id >= 2, ignore - > VALIDATION_FAILURE_1); ValidatorEtr<Bean, ValidationFailure> validatorEtr3 = bean -> bean.map(Bean :: getId).filterOrElse(id - > id <= 2, ignore - > VALIDATION_FAILURE_2); var config = ValidationConfig.<Bean, ValidationFailure>toValidate() .withValidatorEtrs(validatorChain) .prepare(); Hook ValidatorEtrs with Config List<ValidatorEtr<Bean, ValidationFailure >> VALIDATOR_ETRS = List.of(validatorEtr1, validatorEtr2, validatorEtr3); var result = Vader.validateAndFailFast(VALIDATABLE, validationConfig);
  34. Config does more than hooking validators @GopalAkshintala Built-in Validators Plug-&-Play

  35. @GopalAkshintala Configure Mandatory field s Strict SF ID field validation

    s Multi-Filter conditions to handle duplicates in a batc h Min/Max batch size check with combination of multiple batch members Validators Plug-&-Play
  36. @GopalAkshintala Configure Mandatory Fields ValidationConfig.<Bean, ValidationFailure>toValidate() .shouldHaveFieldsOrFailWithFn(Tuple.of( List.of( Bean ::

    getRequiredField1, Bean :: getRequiredField2, Bean :: getRequiredList), (missingFldName, missingFldValue) -> getFailureWithParams(REQUIRED_FIELD_MISSING, missingFldName, missingFldValue))) .prepare();
  37. @GopalAkshintala Configure Mandatory field s Strict SF ID field validation

    s Multi-Filter conditions to handle duplicates in a batc h Min/Max batch size check with combination of multiple batch members Validators Plug-&-Play
  38. @GopalAkshintala Configure SF ID Fields ValidationConfig.<BeanWithIdFields, ValidationFailure>toValidate() .withIdConfig( IDConfig.<BeanWithIdFields, ValidationFailure,

    EntityId>toValidate() .withIdValidator(ValidIdUtil :: isThisEntity) .shouldHaveValidSFIdFormatForAllOrFailWithFn(Tuple.of( Map.of( BeanWithIdFields : : getAccountId, AccountUddConstants.EntityId, BeanWithIdFields : : getContactId, ContactUddConstants.EntityId), (invalidIdFldName, invalidIdFldValue) -> getFailureWithParams(INVALID_UDD_ID, invalidIdFldName, invalidIdFldValue)))) .prepare();
  39. @GopalAkshintala Configure Mandatory field s Strict SF ID field validation

    s Multi-Filter conditions to handle duplicates in a batc h Min/Max batch size check with combination of multiple batch members Plug-&-Play Validators
  40. @GopalAkshintala Configure Multi-Filter for Batch BatchValidationConfig.<MultiKeyBean, ValidationFailure>toValidate() .findAndFilterDuplicatesConfigs(List.of( FilterDuplicatesConfig.<MultiKeyBean, ValidationFailure>toValidate()

    .findAndFilterDuplicatesWith(id1Mapper) .andFailDuplicatesWith(DUPLICATE_ITEM_1), FilterDuplicatesConfig.<MultiKeyBean, ValidationFailure>toValidate() .findAndFilterDuplicatesWith(id2Mapper) .andFailDuplicatesWith(DUPLICATE_ITEM_2))) .prepare();
  41. @GopalAkshintala Configure Mandatory field s Strict SF ID field validation

    s Multi-Filter conditions to handle duplicates in a batc h Min/Max batch size check with combination of multiple batch member s Specs Validators Plug-&-Play
  42. @GopalAkshintala Configure Batch-Size ContainerValidationConfig.<ContainerWithMultiBatch, ValidationFailure>toValidate() .withBatchMappers(List.of( ContainerWithMultiBatch :: getBatch1, ContainerWithMultiBatch

    :: getBatch2)) .shouldHaveMinBatchSizeOrFailWith(Tuple.of(1, MIN_BATCH_SIZE_NOT_MET)) .shouldHaveMaxBatchSizeOrFailWith(Tuple.of(10, MAX_BATCH_SIZE_EXCEEDED)) .prepare();
  43. @GopalAkshintala Configure Mandatory field s Strict SF ID field validation

    s Multi-Filter conditions to handle duplicates in a batc h Min/Max batch size check with combination of multiple batch member s Specs Validators Plug-&-Play
  44. @GopalAkshintala Specs 🤓 Low-code Validations spec._2() .when(Bean :: getStartDate) .then(Bean

    :: getEndDate) .shouldRelateWithFn(isOnOrBeforeIfBothArePresent()) .orFailWith(ofFieldIntegrity(INVALID_START_AND_END_DATES))
  45. @GopalAkshintala Specs 🤓 Low-code Validations ValidationConfig.<Bean, ValidationFailure>toValidate() .specify(spec -> List.of(

    spec._2(). ... , spec._1(), ... , . .. )) .prepare();
  46. @GopalAkshintala DSL Driven Config ValidationConfig.<Bean, ValidationFailure>toValidate() .shouldHaveFieldsOrFailWithFn(…) .withIdConfig(…) .findAndFilterDuplicatesConfigs(…) .specify(…)

    .withValidators(…) .… .prepare();
  47. @GopalAkshintala You don’t need to write Tests for Config 🙊

  48. @GopalAkshintala Think of it as a Type-Safe XML Config is

    NOT Code!
  49. @GopalAkshintala Nested Config for Beans with Nested DS

  50. @GopalAkshintala BatchOfBatch1ValidationConfig.<Item, Bean, ValidationFailure>toValidate() .shouldHaveFieldOrFailWith(Item :: getId, INVALID_ITEM) .withMemberBatchValidationConfig( Tuple.of(Item

    : : getBeanBatch, memberBatchValidationConfig)) .prepare();
  51. @GopalAkshintala 🎛 Config based Validation Perks🍫 Low Learning-curv e Readabilit

    y Maintainabilit y Less Complexit y Testabilit y Flexibilit y Extensibilit y Re-usability/Sharing
  52. @GopalAkshintala Vader Not only for Advanced validation requirements It makes

    simple ones even Simpler!
  53. @GopalAkshintala Vade r Current Applications Connect REST API Validation s

    SObject Validation hook s FTests But it’s Generic! Independent of Consumer’s Implementation
  54. @GopalAkshintala Stable & Actively Maintained Vader

  55. @GopalAkshintala How to trust its Stability & Security? Vader

  56. @GopalAkshintala Vader bit.ly/vader-gh Wanna Collab & Contribute?

  57. @GopalAkshintala bit.ly/vader-slides