A set of declarative validators for Pharo accessors, inspired by JSR-380 Java Bean Validation annotations.
- Make a class, declare several inst vars and generate their corresponsing accessors.
Object subclass: #RegistrationRequest
instanceVariableNames: 'username name password emails'
classVariableNames: ''
package: 'MyApplication-DataTransfer'
- Annotate the accessors with desired validators. 1),2)
2.1 Simple validation
username
<validateAs: 'string'> "should be a string"
<validateAs: 'notBlank'> "notBlank ~ should not be an empty string or whitespace"
^ username
2.2 Collection validation (note that ALL collection elements must conform to the declared validation pragmas)
emails
<validateAs: '#string'>
<validateAs: '#email'> "the '#' signifies that emails shoule be a collection"
"the 'email' signifies that each element of the collection"
"should be a string containing a valid email"
^ emails
- Validate the object once filled. If the validations find a problem,
PragmaValidationError
will be raised.
| r |
r := RegistrationRequest new username: 'john'; emails: {'john@smalltalk.com'. 'jsmith@acme.com'}; validate.
- Note that annotating a mutator or an accessor with a protocol different than "accessing" will not work.
2)The accessors are called in the process of validation, thus one must add additional code to them with caution.
Validation | Usage Example | Description |
---|---|---|
notNil |
<validateAs: 'notNil'> |
Accessor value is not nil |
assertTrue |
<validateAs: 'assertTrue'> |
Accessor value |
size:MIN,MAX |
<validateAs: 'size:1,3'> |
Accessor value has a size between the attributes MIN and MAX; can be applied to any collection |
min:VAL |
<validateAs: 'min:100'> |
Accessor value has a value no smaller than VAL |
max:VAL |
<validateAs: 'max:1000'> |
Accessor value has a value no larger than VAL |
email |
<validateAs: 'email'> |
Accessor value is a valid email address |
notEmpty |
<validateAs: 'notEmpty'> |
Accessor value is not null or empty; can be applied to any collection |
notBlank |
<validateAs: 'notBlank'> |
Accessor value is not null, empty string or string containing solely whitespace |
positive |
<validateAs: 'positive'> |
Accessor value is strictly positive number |
positiveOrZero |
<validateAs: 'positiveOrZero'> |
Accessor value is strictly positive number, or 0 |
negative |
<validateAs: 'negative'> |
Accessor value is strictly negative number |
negativeOrZero |
<validateAs: 'negativeOrZero'> |
Accessor value is strictly negative number, or 0 |
datetimeString |
<validateAs: 'datetimeString'> |
Accessor value is a string containing date and time |
past |
<validateAs: 'past'> |
Accessor value is a string containing date and time which is in the past |
future |
<validateAs: 'future'> |
Accessor value is a string containing date and time which is in the future |
Metacello new
baseline: 'PragmaValidators';
repository: 'github://radekbusa/Pragma-Validators';
load.
Let's say that we want to use the pragma validators for validating JSON request bodies in our RESTful API.
- In a controller or a Teapot filter, write:
| body parsedBody |
body := aRequest entity string.
parsedBody := NeoJSONReader fromString: body as: RegistrationRequest.
parsedBody validate. "will validate each incoming request body"
Tested in Pharo 7, 8 and 9.
Radek Busa is the author and maintainer of this project.
- Tech blog: www.medium.com/@radekbusa
- Hire me for your next Smalltalk project: www.radekbusa.eu
"I love building enterprise-grade software products in no time and Pharo greatly contributes to that with its amazing debugger, test-driven environment and other great stuff, such as refactoring tools. My vision is to build libraries for ultra-productive enterprise microservice development with minimalistic and easy-to-grasp APIs for Smalltalk in 2020s."
If you endorse my vision and/or this project helped you, please don't hesitate to donate. Your donations will be welcome!