@sot1986/appsync-precognition
v0.5.9
Published
JavaScript resolver validation utilities for AWS AppSync
Maintainers
Readme
appsync-precognition
Lean validation library for AppSync JS runtime, implementing Precognition protocol for real-time form validation.
Table of Contents
- Installation
- Basic Usage
- Validation Rules
- Nested Object Validation
- Array Validation
- Custom Error Messages
- Custom Attribute Names
- Validation Options
- Precognitive Validation Features
- Internationalization
- Error Handling
- Advanced Usage
Installation
npm install appsync-precognitionBasic Usage
Simple Validation
Any valid object can be validated, using simplified validation rules.
import { validate } from 'appsync-precognition'
export function request(ctx) {
const validatedArgs = validate({
name: 'Marco',
age: 15,
email: '[email protected]',
}, {
name: ['required', ['min', 3]],
age: ['required', ['min', 18]],
email: ['required', 'email'],
phone: ['sometimes', 'phone']
})
return {
operation: 'PutItem',
key: util.dynamodb.toMapValues({ id: util.autoId() }),
attributeValues: util.dynamodb.toMapValues(validatedArgs)
}
}This validation will throw an Error of type ValidationError.
util.error(
'age min value is 18',
'ValidationError',
null,
{
path: 'age',
value: 15
}
)Precognitive Validation (Real-time)
If your frontend application supports precognitive validation like Nuxt precognition, everything will be handled automatically.
import { precognitiveValidation } from 'appsync-precognition'
export function request(ctx) {
const validatedArgs = precognitiveValidation(ctx, {
name: ['required', ['min', 3]],
age: ['required', ['min', 18]],
email: ['required', 'email'],
phone: ['nullable', 'phone']
})
return {
operation: 'PutItem',
key: util.dynamodb.toMapValues({ id: util.autoId() }),
attributeValues: util.dynamodb.toMapValues(validatedArgs)
}
}- Module checks for precognition headers and/or keys.
- Validates the request payload accordingly
- In case of success and precognitive requests, it will immediately return with
{ data: null, errors: undefined }
Validation Rules
Basic Rules
required- Field must have a valuenullable- Field can be null but validates if presentsometimes- Field is optional but validates if present
Type Rules
string- Must be a stringnumber- Must be a numberboolean- Must be a booleanarray- Must be an arrayobject- Must be an object
String Validation
email- Valid email formatphone- Valid phone number (+123...)url- Valid URL formatuuid- Valid UUID formatulid- Valid ULID format
Date/Time Validation
date- Valid date (YYYY-MM-DD)time- Valid time (HH:MM:SS)datetime- Valid ISO datetime
Numeric Validation
integer- Valid integernumeric- Valid number format
Size Constraints
['min', number]- Minimum value/length['max', number]- Maximum value/length['between', min, max]- Between values (inclusive)['bigger', number]- Strictly greater than['lower', number]- Strictly less than['within', min, max]- Strictly between values
Pattern Matching
['regex', pattern]- Match regex pattern['in', ...values]- Value must be in list['notIn', ...values]- Value must not be in list
Date Comparisons
['before', date]- Before specified date['after', date]- After specified date['beforeOrEqual', date]- Before or equal to date['afterOrEqual', date]- After or equal to date
Nested Object Validation
const validatedArgs = validate(ctx.args, {
'user.name': ['required', ['min', 3]],
'user.email': ['required', 'email'],
'address.street': ['required'],
'address.zipCode': ['required', ['between', 5, 10]]
})Array Validation
To simplify error rules definition, the shortcut * is supported.
const validatedArgs = validate(ctx.args, {
'hobbies': ['required', 'array', ['min', 1]],
'hobbies.*': ['required', 'string', ['max', 50]], // Validates each array item
'tags': ['sometimes', 'array'],
'tags.*.value': ['string']
})Custom Error Messages
const validatedArgs = validate(ctx.args, {
email: [{ rule: 'email', msg: 'Please enter a valid email address' }],
age: [{ rule: ['min', 18], msg: 'You must be at least 18 years old' }]
})Custom Attribute Names
Attribute names can be customized by adding a third parameter to the validate function.
const validatedArgs = validate(ctx.args, {
'email': ['required', 'email'],
'phone': ['required', 'phone'],
'hobbies.*': ['required', ['min', 2]] // each hobbies should have at least 2 chars
}, {
attributes: {
':email': 'Email Address',
':phone': 'Phone Number',
':hobbies.*': 'Hobby' // 'Hobby must have at least 2 characters'
}
})Validation Options
const validatedArgs = validate(ctx.args, rules, {
trim: true, // Trim string values (default: true)
allowEmptyString: false, // Allow empty strings (default: false)
errors: {
required: ':attr is mandatory',
email: ':attr must be a valid email'
},
attributes: {
':email': 'Email Address'
}
})Precognitive Validation Features
The precognitiveValidation function automatically handles:
- Full validation when
precognitionheader is not present - Selective validation when
precognition-validate-onlyheader specifies fields - Early return for precognitive requests with proper headers
- Response headers for client-side precognition handling
Client Integration
Your frontend should send these headers for precognitive validation:
{
"Precognition": "true",
"Precognition-Validate-Only": "email,name"
}In addition, these headers must be enabled in the CORS policy of AppSync.
Internationalization
import { localize } from 'appsync-precognition/i18n'
export function request(ctx) {
// Set up localization based on Accept-Language header
localize(ctx, {
errors: {
en: { required: ':attr is required' },
es: { required: ':attr es requerido' },
it: { required: 'il campo :attr è obbligatorio' }
},
attributes: {
en: { ':name': 'Name', ':email': 'Email' },
es: { ':name': 'Nombre', ':email': 'Correo' },
it: { ':name': 'Nome', ':email': 'Email' }
}
}) // locale details will be added in stash object
const validatedArgs = precognitiveValidation(ctx, {
name: ['required'],
email: ['required', 'email']
})
return { /* your operation */ }
}If needed, it can be useful to split the localization and validation in separate resolvers of the same pipeline.
Error Handling
Validation errors are thrown as AppSync errors with detailed information:
// When validation fails, the error contains:
// - message: Human-readable error message
// - errorType: 'ValidationError'
// - errorInfo: { path: 'field.name', value: invalidValue }Advanced Usage
Assert Validated Data
import { assertValidated } from 'appsync-precognition'
export function request(ctx) {
precognitiveValidation(ctx, rules)
return { /* operation */ }
}
export function response(ctx) {
assertValidated(ctx) // Ensures validation was performed
return ctx.stash.__validated
}Check Localization
import { assertLocalized, isLocalized } from 'appsync-precognition'
export function request(ctx) {
if (isLocalized(ctx, 'es')) {
// Handle Spanish localization
}
assertLocalized(ctx) // Throws if not localized
}