Skip to content

Repository files navigation

Speck

Speck - Let you create your domain entities with reactive validation based on ReactpropTypes

Build Status

This package let you create entities with schema validation based on React PropTypes.

Installing

$ npm install speck-entity

Using

Sample Entities

constJoi=require('joi')constjoiAdapter=require('validatorAdapters')('joi',Joi)constSpeck=require('speck-entity')classMyEntityextendsSpeck{staticSCHEMA={field: joiAdapter(Joi.string()),otherField: {validator: joiAdapter(Joi.number()),defaultValue: 10}}}classFatherEntityextendsSpeck{staticSCHEMA={children: {validator: joiAdapter(Joi.array().items(Joi.object().type(MyEntity)))type: MyEntity}}}

Get default values

constniceInstance=newMyEntity();console.log(niceInstance.toJSON());// { field: undefined, otherField: 10 }console.log(niceInstance.errors);// {}

Validations

constbuggedInstance=newMyEntity({field: 10,otherField: 'value'});console.log(buggedInstance.toJSON());// { field: 10, otherField: 'value' }console.log(buggedInstance.errors);/* or buggedInstance.getErrors() -- but... getErrors also includes children errors { field: { errors: [ 'Invalid undefined `field` of type `number` supplied to `MyEntityEntity`, expected `string`.' ] }, otherField: { errors: [ 'Invalid undefined `otherField` of type `string` supplied to `MyEntityEntity`, expected `number`.' ] } }*/

Validate on change value

constotherInstance=newMyEntity({field: 'myString'});console.log(otherInstance.errors);// {}console.log(otherInstance.valid);// trueotherInstance.field=1;console.log(otherInstance.errors);// {field: { errors: [ 'Invalid undefined `field` of type `number` supplied to `MyEntityEntity`, expected `string`.' ] }}console.log(otherInstance.valid);// false

Parse children to Entity

constfatherInstance=newFatherEntity({children: [{field: 'A',otherField: 2},{field: 'B',otherField: 3}]})console.log(fatherInstance.children[0]);//An instance of MyEntityconsole.log(fatherInstance.children[1].toJSON());//{ field: 'B', otherField: 3 }

Builder

When you need to create objects with custom verification like

constelementList={elements: [{type: 'product',name: true,price: true},{type: 'default',isDefault: true}]};

In such cases you can define a builder as follows:

classElementListextendsSpeck{}ElementList.SCHEMA={elements: {validator: noop,builder: (dataList,Type,dependencies)=>dataList.map(data=>{if(data.type==='product')returnnewProductEntity(data,dependencies);if(data.type==='default')returnnewFakeEntityWithBoolean(data);})}};

And use it like:

newElementList(elementList,someDependency)

(note that you can pass custom dependencies to your child entities and latter access them on the builder)

By defining builder you tell Speck Entity that you take the responsibility of instansitating and returning a new object of the type which suits you the best. This is a powerful concept as it lets users dynamically create new types on the fly.

Clean unexpected values

constanotherInstance=newMyEntity({field: 'myString',fake: 'fake'});console.log(anotherInstance.toJSON());// { field: 'myString', otherField: 10 }

To understand the validators React PropTypes

Well known issues

  • Create helpers for relationships validations(Like, mininum, maximum)
  • Create identifier and equal comparison
  • Type builders and/or custom builders are not being applied on instance setters

Contextual validation

classFakeEntityWithExcludeContextextendsSpeck{staticSCHEMA={id: joiAdapter(Joi.number().required()),requiredProp1: joiAdapter(Joi.number().required()),requiredProp2: joiAdapter(Joi.number().required()),requiredProp3: joiAdapter(Joi.number().required())}staticCONTEXTS={create: {exclude: ['requiredProp2','requiredProp3']},edit: {include: ['id','requiredProp1','requiredProp2']},onlyId: {include: ['id']}}}constmyEntity=newFakeEntityWithIncludeContext({id: 1});constcontextCreate=myEntity.validateContext('create');console.log(contextCreate.errors);// { requiredProp1: { errors: [ ... ] }}console.log(contextCreate.valid);// falseconstcontextEdit=myEntity.validateContext('edit');console.log(contextEdit.errors);// { requiredProp1: { errors: [ ... ] }, requiredProp2: { errors: [ ... ] } }console.log(contextEdit.valid);// falseconstcontextOnlyId=myEntity.validateContext('onlyId')console.log(contextOnlyId.errors);// {}console.log(contextOnlyId.valid);// true

Each context (create and edit in example above), could have include property OR exclude, the include property receives the properties that will be validated in this context, and the exclude property represents the properties that will be ignored on validation.

In the example, the create context, will only check the 'requiredProp1' and 'requiredProp2' fields, and the edit context will check 'requiredProp1', 'requiredProp2' and 'id' properties.

You can't combine include and exclude in the same context definition

##Custom validation You can validate your entity adding the property in fields and setting the new validator

classEntityextendsSpeck{staticSCHEMA={id: joiAdapter(Joi.number().required()),requiredProp1: joiAdapter(Joi.number().required())}staticCONTEXTS={create: {fields: {requiredProp1: (obj,field)=>{if(obj[field]===-1)returnnewError('Error -1');}}}}}constentity=newEntity({id: 1,requiredProp1: -1});constcontextValidated=entity.validateContext('create');console.log(entity.errors.requiredProp1);// undefinedconsole.log(contextValidated.requiredProp1);// { errors: [Error: Error -1] }

Hooks

classEntityWithHookextendsSpeck{staticSCHEMA={fieldWithHook: {validator: joiAdapter(Joi.number()),hooks: {afterSet(data,fieldName){// data is the whole data of the instance// fieldName the current fieldName// DO WHATEVER YOU WANT}}},anotherFieldWithHook: {validator: joiAdapter(Joi.number()),hooks: {afterSet(data,fieldName){return{anotherField: data[fieldName]*2}// if the afterSet hook returns an object is merged to data}}},anotherField: joiAdapter(Joi.number()),}}constmyEntity=newEntityWithHook({fieldWithHook: 'foo',anotherFieldWithHook: 'bar',anotherField: null});myEntity.anotherFieldWithHook=10//according to the after set hook anotherField newValue will be 20

About

Domain entities with reactive validation

Resources

Code of conduct

Stars

100 stars

Watchers

26 watching

Forks

Releases

Packages

Used by

Contributors

Languages