ValidModel
ValidModel enhances application models and makes data safer to handle and easier to reason about.
In many cases projects are stuffed with 'mocks'. They provide good value however it comes with a price of extra development and maintanence that mock loading system and mock files require (source code that loads mock data, mock data files that are supposed to match model's format).
In a nutshell ValidModel proposes a different workflow when working with application models and it boils down to an idea of Validation. Assume having a model with clearly defined min-max range values for all required properties of the model. By just knowing min-max limits information it is easy to:
- confirm that given model instance contains correct values that application knows how to handle.
- generate new instance(s) of this model for easy testing, N times (whether you work on UI edge case or API that is not available yet, this instance is just like an object from mock data, but autogenerated, N times).
Implementation wise it requires to define model contract. Having defined model named MyModel - define MyModelContract. In MyModelContract - describe property types and constrains of MyModel.
Essentially Contract describes constraints of the properties, its' types and range of values that properties supposed to have. For example, consider having a User model:
struct User: Decodable {
var firstName: String
var email: String
}
create UserContract and describe types of values that suit 'email' and 'firstName' properties best:
struct UserContract: ModelContract {
typealias M = User // UserContract describes concrete contract for 'User' model.
typealias P = PropertyPolicy
// 'email' name matches User.email property = (KeyPath \M.email targets User.email, validator 'EmailValidator' explicitly describes property value)
let email: P = (\M.email, EmailValidator())
// 'firstName' name matches User.firstName = (KeyPath \M.firstName targets User.firstName property, validator 'StringValidator' explicitly constrains value to be a String of 1-30 chars length)
let firstName: P = (\M.firstName, StringValidator(length: (min: 1, max: 30)))
}
Having described a contract it is easy to:
- validate model instance
- generate dummy instance (for testing purposes, etc)
Here is how it looks like in code:
let validator = ModelValidator() // instantiate model validator once and reuse later.
let user: User = ... // assuming instance exists, from API response and JSONDecod-ed into object.
let contract = UserContract()
// Validate model instance:
let isValid = try? validator.validate(user, using: contract)
let generator = ModelGenerator() // instantiate once and reuse later.
// Generate new instance with 'random' values for testing purposes:
let dummyUser: User = try? generator.model(from: contract, aggregate: .random)
Example
To run the example project, clone the repo, and run pod install
from the Example directory first.
Installation
ValidModel is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod 'ValidModel'
Base version only:
pod 'ValidModel/Base'
- includes only: 'StringValidator', 'IntValidator' and 'DoubleValidator'.
Extended version:
pod 'ValidModel/Extended'
- provides more validators(EmailValidator, LastNameValidator, etc) but has extra dependency on 'Fakery' pod.
Author
kernel, ReImpl.
License
ValidModel is available under the MIT license. See the LICENSE file for more info.