1 | 'use strict'
|
2 |
|
3 | const headersSchema = Symbol('headers-schema')
|
4 | const paramsSchema = Symbol('params-schema')
|
5 | const querystringSchema = Symbol('querystring-schema')
|
6 | const bodySchema = Symbol('body-schema')
|
7 |
|
8 | const responseSchema = Symbol('response-schema')
|
9 |
|
10 | function compileSchemasForSerialization (context, compile) {
|
11 | if (!context.schema || !context.schema.response) {
|
12 | return
|
13 | }
|
14 |
|
15 | const { method, url } = context.config || {}
|
16 | context[responseSchema] = Object.keys(context.schema.response)
|
17 | .reduce(function (acc, statusCode) {
|
18 | acc[statusCode] = compile({
|
19 | schema: context.schema.response[statusCode],
|
20 | url,
|
21 | method,
|
22 | httpStatus: statusCode
|
23 | })
|
24 | return acc
|
25 | }, {})
|
26 | }
|
27 |
|
28 | function compileSchemasForValidation (context, compile) {
|
29 | if (!context.schema) {
|
30 | return
|
31 | }
|
32 |
|
33 | const { method, url } = context.config || {}
|
34 |
|
35 | const headers = context.schema.headers
|
36 | if (headers && Object.getPrototypeOf(headers) !== Object.prototype) {
|
37 |
|
38 | context[headersSchema] = compile({ schema: headers, method, url, httpPart: 'headers' })
|
39 | } else if (headers) {
|
40 |
|
41 |
|
42 | const headersSchemaLowerCase = {}
|
43 | Object.keys(headers).forEach(k => { headersSchemaLowerCase[k] = headers[k] })
|
44 | if (headersSchemaLowerCase.required instanceof Array) {
|
45 | headersSchemaLowerCase.required = headersSchemaLowerCase.required.map(h => h.toLowerCase())
|
46 | }
|
47 | if (headers.properties) {
|
48 | headersSchemaLowerCase.properties = {}
|
49 | Object.keys(headers.properties).forEach(k => {
|
50 | headersSchemaLowerCase.properties[k.toLowerCase()] = headers.properties[k]
|
51 | })
|
52 | }
|
53 | context[headersSchema] = compile({ schema: headersSchemaLowerCase, method, url, httpPart: 'headers' })
|
54 | }
|
55 |
|
56 | if (context.schema.body) {
|
57 | context[bodySchema] = compile({ schema: context.schema.body, method, url, httpPart: 'body' })
|
58 | }
|
59 |
|
60 | if (context.schema.querystring) {
|
61 | context[querystringSchema] = compile({ schema: context.schema.querystring, method, url, httpPart: 'querystring' })
|
62 | }
|
63 |
|
64 | if (context.schema.params) {
|
65 | context[paramsSchema] = compile({ schema: context.schema.params, method, url, httpPart: 'params' })
|
66 | }
|
67 | }
|
68 |
|
69 | function validateParam (validatorFunction, request, paramName) {
|
70 | var ret = validatorFunction && validatorFunction(request[paramName])
|
71 | if (ret === false) return validatorFunction.errors
|
72 | if (ret && ret.error) return ret.error
|
73 | if (ret && ret.value) request[paramName] = ret.value
|
74 | return false
|
75 | }
|
76 |
|
77 | function validate (context, request) {
|
78 | var params = validateParam(context[paramsSchema], request, 'params')
|
79 |
|
80 | if (params) {
|
81 | return wrapValidationError(params, 'params', context.schemaErrorFormatter)
|
82 | }
|
83 | var body = validateParam(context[bodySchema], request, 'body')
|
84 | if (body) {
|
85 | return wrapValidationError(body, 'body', context.schemaErrorFormatter)
|
86 | }
|
87 | var query = validateParam(context[querystringSchema], request, 'query')
|
88 | if (query) {
|
89 | return wrapValidationError(query, 'querystring', context.schemaErrorFormatter)
|
90 | }
|
91 | var headers = validateParam(context[headersSchema], request, 'headers')
|
92 | if (headers) {
|
93 | return wrapValidationError(headers, 'headers', context.schemaErrorFormatter)
|
94 | }
|
95 | return null
|
96 | }
|
97 |
|
98 | function wrapValidationError (result, dataVar, schemaErrorFormatter) {
|
99 | if (result instanceof Error) {
|
100 | return result
|
101 | }
|
102 |
|
103 | var error = schemaErrorFormatter(result, dataVar)
|
104 | error.validation = result
|
105 | error.validationContext = dataVar
|
106 | return error
|
107 | }
|
108 |
|
109 | function serialize (context, data, statusCode) {
|
110 | var responseSchemaDef = context[responseSchema]
|
111 | if (!responseSchemaDef) {
|
112 | return JSON.stringify(data)
|
113 | }
|
114 | if (responseSchemaDef[statusCode]) {
|
115 | return responseSchemaDef[statusCode](data)
|
116 | }
|
117 | var fallbackStatusCode = (statusCode + '')[0] + 'xx'
|
118 | if (responseSchemaDef[fallbackStatusCode]) {
|
119 | return responseSchemaDef[fallbackStatusCode](data)
|
120 | }
|
121 | return JSON.stringify(data)
|
122 | }
|
123 |
|
124 | module.exports = {
|
125 | symbols: { bodySchema, querystringSchema, responseSchema, paramsSchema, headersSchema },
|
126 | compileSchemasForValidation,
|
127 | compileSchemasForSerialization,
|
128 | validate,
|
129 | serialize
|
130 | }
|