forked from middyjs/middy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
validator.js
114 lines (91 loc) · 2.71 KB
/
validator.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
const createError = require('http-errors')
const Ajv = require('ajv')
const ajvKeywords = require('ajv-keywords')
const ajvLocalize = require('ajv-i18n')
const { deepStrictEqual } = require('assert')
let ajv
let previousConstructorOptions
const defaults = {
v5: true,
coerceTypes: 'array', // important for query string params
allErrors: true,
useDefaults: true,
$data: true, // required for ajv-keywords
defaultLanguage: 'en'
}
const availableLanguages = Object.keys(ajvLocalize)
/* in ajv-i18n Portuguese is represented as pt-BR */
const languageNormalizationMap = {
'pt': 'pt-BR',
'pt-br': 'pt-BR',
'pt_BR': 'pt-BR',
'pt_br': 'pt-BR'
}
const normalizePreferredLanguage = (lang) => languageNormalizationMap[lang] || lang
const chooseLanguage = ({ preferredLanguage }, defaultLanguage) => {
if (preferredLanguage) {
const lang = normalizePreferredLanguage(preferredLanguage)
if (availableLanguages.includes(lang)) {
return lang
}
}
return defaultLanguage
}
module.exports = ({ inputSchema, outputSchema, ajvOptions }) => {
const options = Object.assign({}, defaults, ajvOptions)
lazyLoadAjv(options)
const validateInput = inputSchema ? ajv.compile(inputSchema) : null
const validateOutput = outputSchema ? ajv.compile(outputSchema) : null
return {
before (handler, next) {
if (!inputSchema) {
return next()
}
const valid = validateInput(handler.event)
if (!valid) {
const error = new createError.BadRequest('Event object failed validation')
handler.event.headers = Object.assign({}, handler.event.headers)
const language = chooseLanguage(handler.event, options.defaultLanguage)
ajvLocalize[language](validateInput.errors)
error.details = validateInput.errors
throw error
}
return next()
},
after (handler, next) {
if (!outputSchema || (!handler.response && handler.error)) {
return next()
}
const valid = validateOutput(handler.response)
if (!valid) {
const error = new createError.InternalServerError('Response object failed validation')
error.details = validateOutput.errors
error.response = handler.response
throw error
}
return next()
}
}
}
function lazyLoadAjv (options) {
if (shouldInitAjv(options)) {
initAjv(options)
}
return ajv
}
function shouldInitAjv (options) {
return !ajv || areConstructorOptionsNew(options)
}
function areConstructorOptionsNew (options) {
try {
deepStrictEqual(options, previousConstructorOptions)
} catch (e) {
return true
}
return false
}
function initAjv (options) {
ajv = new Ajv(options)
ajvKeywords(ajv)
previousConstructorOptions = options
}