UNPKG

4.26 kBJavaScriptView Raw
1'use strict'
2
3const headersSchema = Symbol('headers-schema')
4const paramsSchema = Symbol('params-schema')
5const querystringSchema = Symbol('querystring-schema')
6const bodySchema = Symbol('body-schema')
7
8const responseSchema = Symbol('response-schema')
9
10function 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
28function 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 // do not mess with non-literals, e.g. Joi schemas
38 context[headersSchema] = compile({ schema: headers, method, url, httpPart: 'headers' })
39 } else if (headers) {
40 // The header keys are case insensitive
41 // https://tools.ietf.org/html/rfc2616#section-4.2
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
69function 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
77function 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
98function 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
109function 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
124module.exports = {
125 symbols: { bodySchema, querystringSchema, responseSchema, paramsSchema, headersSchema },
126 compileSchemasForValidation,
127 compileSchemasForSerialization,
128 validate,
129 serialize
130}