UNPKG

openapi-request-coercer

Version:
264 lines 11.3 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; exports.__esModule = true; var ts_log_1 = require("ts-log"); var OpenAPIRequestCoercer = /** @class */ (function () { function OpenAPIRequestCoercer(args) { var loggingKey = args && args.loggingKey ? "".concat(args.loggingKey, ": ") : ''; if (!args) { throw new Error("".concat(loggingKey, "missing args argument")); } var logger = args.logger || ts_log_1.dummyLogger; if (!Array.isArray(args.parameters)) { throw new Error("".concat(loggingKey, "args.parameters must be an Array")); } if (!args.coercionStrategy) { args.coercionStrategy = {}; } var extensionBase = args && args.extensionBase ? args.extensionBase : 'x-openapi-coercion'; var strictExtensionName = "".concat(extensionBase, "-strict"); var enableObjectCoercion = !!args.enableObjectCoercion; this.coerceHeaders = buildCoercer({ params: args.parameters, property: 'header', isHeaders: true, logger: logger, loggingKey: loggingKey, strictExtensionName: strictExtensionName, enableObjectCoercion: enableObjectCoercion, coercionStrategy: args.coercionStrategy }); this.coerceParams = buildCoercer({ params: args.parameters, property: 'path', isHeaders: false, logger: logger, loggingKey: loggingKey, strictExtensionName: strictExtensionName, enableObjectCoercion: enableObjectCoercion, coercionStrategy: args.coercionStrategy }); this.coerceQuery = buildCoercer({ params: args.parameters, property: 'query', isHeaders: false, logger: logger, loggingKey: loggingKey, strictExtensionName: strictExtensionName, enableObjectCoercion: enableObjectCoercion, coercionStrategy: args.coercionStrategy }); this.coerceFormData = buildCoercer({ params: args.parameters, requestBody: args.requestBody, property: 'formData', isHeaders: false, logger: logger, loggingKey: loggingKey, strictExtensionName: strictExtensionName, enableObjectCoercion: enableObjectCoercion, coercionStrategy: args.coercionStrategy }); } OpenAPIRequestCoercer.prototype.coerce = function (request) { if (request.headers && this.coerceHeaders) { this.coerceHeaders(request.headers); } if (request.params && this.coerceParams) { this.coerceParams(request.params); } if (request.query && this.coerceQuery) { this.coerceQuery(request.query); } if (request.body && this.coerceFormData) { this.coerceFormData(request.body); } }; return OpenAPIRequestCoercer; }()); exports["default"] = OpenAPIRequestCoercer; function buildCoercer(args) { var _a, _b, _c; if (!args.params.length && !args.requestBody) { return; } var l = args.isHeaders ? function (name) { return name.toLowerCase(); } : function (name) { return name; }; var properties = args.params.filter(byLocation(args.property)); if (args.property === 'formData' && args.requestBody) { var openapiv3formData_1 = (_c = (_b = (_a = args.requestBody) === null || _a === void 0 ? void 0 : _a.content['application/x-www-form-urlencoded']) === null || _b === void 0 ? void 0 : _b.schema) === null || _c === void 0 ? void 0 : _c.properties; if (openapiv3formData_1) { properties = properties.concat(Object.keys(openapiv3formData_1).map(function (k) { return __assign(__assign({}, openapiv3formData_1[k]), { name: k }); })); } } var coercers = properties.reduce(function (acc, param) { acc[l(param.name)] = buildCoercerForParam(args, param); return acc; }, {}); return function (obj) { for (var paramName in obj) { if (coercers.hasOwnProperty(l(paramName))) { obj[paramName] = coercers[l(paramName)](obj[paramName]); } } }; } function buildCoercerForParam(args, param) { var logger = args.logger, loggingKey = args.loggingKey, enableObjectCoercion = args.enableObjectCoercion, _a = args.coercionStrategy, customStrategy = _a === void 0 ? {} : _a; var strict = !!param[args.strictExtensionName]; function getCoercer(type) { var OBJECT_FORMAT_COERCER = { "default": function (schema, input) { return JSON.parse(input); }, deepObject: function (schema, input) { for (var _i = 0, _a = Object.keys(input); _i < _a.length; _i++) { var key = _a[_i]; var propertySchema = schema.properties ? schema.properties[key] : schema.additionalProperties; if (propertySchema) { input[key] = getCoercer(propertySchema.type)(propertySchema, input[key]); } } return input; } }; var COERCION_STRATEGIES = { array: function (schema, input) { if (!Array.isArray(input)) { var collectionFormat = param.collectionFormat; // OpenAPI 3.0 has replaced collectionFormat with a style property // https://swagger.io/docs/specification/serialization/ if (param.style) { if (param.style === 'form' && param["in"] === 'query') { collectionFormat = param.explode ? 'multi' : 'csv'; } else if (param.style === 'simple' && (param["in"] === 'path' || param["in"] === 'header')) { collectionFormat = 'csv'; } else if (param.style === 'spaceDelimited' && param["in"] === 'query') { collectionFormat = 'ssv'; } else if (param.style === 'pipeDelimited' && param["in"] === 'query') { collectionFormat = 'pipes'; } } var sep = pathsep(collectionFormat || 'csv'); input = input.split(sep); } return input.map(function (v, i) { var itemSchema = schema.items.schema ? schema.items.schema : schema.items; return getCoercer(itemSchema.type)(itemSchema, v); }); }, object: function (schema, input) { if (!enableObjectCoercion) { return input; } // Similar to arrays, objects support formats. In OpenAPI 3.0, the format is called "style". // Currently this coercer only automatically supports the deepObject style, and a simple // JSON format, though the OpenAPI 3.0 specification defines many styles similar to arrays. var style = param.style || schema.format; var objectCoercer = OBJECT_FORMAT_COERCER[style] || OBJECT_FORMAT_COERCER["default"]; return objectCoercer(schema, input); }, boolean: function (schema, input) { if (typeof input === 'boolean') { return input; } if (input === 'false') { return false; } else { return true; } }, integer: function (schema, input) { var result = Math.floor(Number(input)); return isNaN(result) ? input : result; }, number: function (schema, input) { var result = Number(input); return isNaN(result) ? input : result; }, string: function (schema, input) { return String(input); } }; var STRICT_COERCION_STRATEGIES = { boolean: function (schema, input) { if (typeof input === 'boolean') { return input; } if (input.toLowerCase() === 'false') { return false; } else if (input.toLowerCase() === 'true') { return true; } else { return null; } } }; if (customStrategy[type] !== undefined) { return function (schema, input) { return customStrategy[type](input); }; } if (strict && STRICT_COERCION_STRATEGIES[type] !== undefined) { return STRICT_COERCION_STRATEGIES[type]; } if (COERCION_STRATEGIES[type] !== undefined) { return COERCION_STRATEGIES[type]; } var msg = type === undefined ? 'No type has been defined' : "No proper coercion strategy has been found for type '".concat(type, "'"); logger.warn(loggingKey, "".concat(msg, ". A default 'identity' strategy has been set.")); return function (schema, input) { return input; }; } // OpenAPI (Swagger) 2.0 has type and format information as direct properties // of the param object. OpenAPI 3.0 has type and format information in a // schema object property. Use a schema value to normalize the change across // both versions so coercer works properly. var paramOrSchema = param.schema || param; if (paramOrSchema.type === 'array') { if (!paramOrSchema.items) { throw new Error("".concat(args.loggingKey, "items is a required property with type array")); } if (paramOrSchema.items.type === 'array' || (paramOrSchema.items.schema && paramOrSchema.items.schema.type === 'array')) { throw new Error("".concat(args.loggingKey, "nested arrays are not allowed (items was of type array)")); } } return getCoercer(paramOrSchema.type).bind(null, paramOrSchema); } function byLocation(location) { return function (param) { return param["in"] === location; }; } function pathsep(format) { switch (format) { case 'csv': return ','; case 'ssv': return ' '; case 'tsv': return '\t'; case 'pipes': return '|'; } } //# sourceMappingURL=index.js.map