forked from middyjs/middy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
128 lines (103 loc) · 3.11 KB
/
index.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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
const createError = require('http-errors')
const Ajv = require('ajv')
const { deepStrictEqual } = require('assert')
let ajv
let previousConstructorOptions
const optionsDefault = {
v5: true,
coerceTypes: 'array', // important for query string params
allErrors: true,
useDefaults: true,
$data: true, // required for ajv-keywords
defaultLanguage: 'en',
jsonPointers: true
}
const pluginsInstances = {}
const pluginsDefault = {
keywords: null,
errors: null,
i18n: null
}
let availableLanguages
/* 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, ajvPlugins }) => {
const options = Object.assign({}, optionsDefault, ajvOptions)
const pluginsOptions = Object.assign({}, pluginsDefault, ajvPlugins)
lazyLoadAjv(options, pluginsOptions)
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)
pluginsInstances.i18n[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, plugins) {
if (shouldInitAjv(options)) {
initAjv(options, plugins)
}
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, pluginsOptions) {
ajv = new Ajv(options)
Object.keys(pluginsOptions).forEach(p => {
pluginsInstances[p] = require(`ajv-${p}`)
if (typeof pluginsInstances[p] === 'function') {
pluginsInstances[p](ajv, pluginsOptions[p])
}
})
availableLanguages = Object.keys(pluginsInstances.i18n)
previousConstructorOptions = options
}