claudia-api-builder
Advanced tools
Comparing version 2.4.1 to 2.4.2
{ | ||
"name": "claudia-api-builder", | ||
"version": "2.4.1", | ||
"version": "2.4.2", | ||
"description": "Simplify AWS ApiGateway handling", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
@@ -1,2 +0,2 @@ | ||
#Claudia API Builder | ||
# Claudia API Builder | ||
@@ -3,0 +3,0 @@ [![npm](https://img.shields.io/npm/v/claudia-api-builder.svg?maxAge=2592000?style=plastic)](https://www.npmjs.com/package/claudia-api-builder) |
# Release history | ||
## 2.4.0, 17 January 2016 | ||
## 2.4.1, 3 May 2017 | ||
- API builder will not explode, but provide a helpful error messahe when invalid or circular JSON structures passed as application/json requests or responses | ||
## 2.4.0, 17 January 2017 | ||
- support for API Gateway Binary content handling | ||
@@ -6,0 +10,0 @@ |
@@ -1,2 +0,3 @@ | ||
const convertApiGWProxyRequest = require('./convert-api-gw-proxy-request'), | ||
const util = require('util'), | ||
convertApiGWProxyRequest = require('./convert-api-gw-proxy-request'), | ||
lowercaseKeys = require('./lowercase-keys'); | ||
@@ -15,2 +16,5 @@ module.exports = function ApiBuilder(options) { | ||
const self = this, | ||
safeStringify = function (object) { | ||
return util.format('%j', object); | ||
}, | ||
getRequestFormat = function (newFormat) { | ||
@@ -24,3 +28,3 @@ const supportedFormats = ['AWS_PROXY', 'CLAUDIA_API_BUILDER']; | ||
} else { | ||
throw 'Unsupported request format ' + newFormat; | ||
throw `Unsupported request format ${newFormat}`; | ||
} | ||
@@ -45,3 +49,3 @@ } | ||
v2DeprecationWarning = function (what) { | ||
logger(what + ' are deprecated, and be removed in claudia api builder v3. Check https://claudiajs.com/tutorials/migrating_to_2.html'); | ||
logger(`${what} are deprecated, and be removed in claudia api builder v3. Check https://claudiajs.com/tutorials/migrating_to_2.html`); | ||
}, | ||
@@ -54,6 +58,3 @@ supportedMethods = ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'PATCH'], | ||
mergeObjects = function (from, to) { | ||
Object.keys(from).forEach(function (key) { | ||
to[key] = from[key]; | ||
}); | ||
return to; | ||
return Object.assign(to, from); | ||
}, | ||
@@ -94,3 +95,7 @@ isRedirect = function (code) { | ||
} else { | ||
return JSON.stringify(contents); | ||
try { | ||
return JSON.stringify(contents); | ||
} catch (e) { | ||
throw new Error('Response contains a circular reference and cannot be serialized to JSON'); | ||
} | ||
} | ||
@@ -103,3 +108,3 @@ } else { | ||
} else if (typeof contents === 'object') { | ||
return JSON.stringify(contents); | ||
return safeStringify(contents); | ||
} else { | ||
@@ -116,3 +121,3 @@ return String(contents); | ||
if (isApiResponse(err)) { | ||
logInfo = JSON.stringify(err); | ||
logInfo = safeStringify(err); | ||
} else if (isError(err)) { | ||
@@ -128,2 +133,5 @@ logInfo = err.stack; | ||
} | ||
if (contents && typeof (contents) !== 'string') { | ||
contents = safeStringify(contents); | ||
} | ||
if (getCanonicalContentType(contentType) === 'application/json') { | ||
@@ -173,3 +181,3 @@ return JSON.stringify({errorMessage: contents || '' }); | ||
} | ||
return Promise.resolve().then(function () { | ||
return Promise.resolve().then(() => { | ||
if (customCorsHandler === false) { | ||
@@ -182,11 +190,12 @@ return ''; | ||
} | ||
}).then(function (corsOrigin) { | ||
return { | ||
'Access-Control-Allow-Origin': corsOrigin, | ||
'Access-Control-Allow-Headers': corsOrigin && (customCorsHeaders || 'Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token'), | ||
'Access-Control-Allow-Methods': corsOrigin && methods.sort().join(',') + ',OPTIONS', | ||
'Access-Control-Allow-Credentials': corsOrigin && 'true', | ||
'Access-Control-Max-Age': customCorsMaxAge || 0 | ||
}; | ||
}); | ||
}) | ||
.then(corsOrigin => { | ||
return { | ||
'Access-Control-Allow-Origin': corsOrigin, | ||
'Access-Control-Allow-Headers': corsOrigin && (customCorsHeaders || 'Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token'), | ||
'Access-Control-Allow-Methods': corsOrigin && methods.sort().join(',') + ',OPTIONS', | ||
'Access-Control-Allow-Credentials': corsOrigin && 'true', | ||
'Access-Control-Max-Age': customCorsMaxAge || 0 | ||
}; | ||
}); | ||
}, | ||
@@ -201,22 +210,22 @@ routeEvent = function (routingInfo, event, context) { | ||
); | ||
return getCorsHeaders(event, Object.keys(routes[routingInfo.path] || {})).then(function (corsHeaders) { | ||
if (routingInfo.method === 'OPTIONS') { | ||
return { | ||
statusCode: 200, | ||
body: '', | ||
headers: corsHeaders | ||
}; | ||
} else if (handler) { | ||
return Promise.resolve().then(function () { | ||
return handler(event, context); | ||
}).then(function (result) { | ||
return packResult(result, routingInfo, corsHeaders, 'success'); | ||
}).catch(function (error) { | ||
logError(error); | ||
return packResult(error, routingInfo, corsHeaders, 'error'); | ||
}); | ||
} else { | ||
return Promise.reject('no handler for ' + routingInfo.method + ' ' + routingInfo.path); | ||
} | ||
}); | ||
return getCorsHeaders(event, Object.keys(routes[routingInfo.path] || {})) | ||
.then(corsHeaders => { | ||
if (routingInfo.method === 'OPTIONS') { | ||
return { | ||
statusCode: 200, | ||
body: '', | ||
headers: corsHeaders | ||
}; | ||
} else if (handler) { | ||
return Promise.resolve() | ||
.then(() => handler(event, context)) | ||
.then(result => packResult(result, routingInfo, corsHeaders, 'success')) | ||
.catch(error => { | ||
logError(error); | ||
return packResult(error, routingInfo, corsHeaders, 'error'); | ||
}); | ||
} else { | ||
return Promise.reject(`no handler for ${routingInfo.method} ${routingInfo.path}`); | ||
} | ||
}); | ||
@@ -251,5 +260,4 @@ }, | ||
} else { | ||
return Promise.resolve().then(function () { | ||
return interceptCallback(request, context); | ||
}); | ||
return Promise.resolve() | ||
.then(() => interceptCallback(request, context)); | ||
} | ||
@@ -334,29 +342,36 @@ }, | ||
self.proxyRouter = function (event, context, callback) { | ||
const request = getRequest(event, context), | ||
handleError = function (e) { | ||
context.done(e); | ||
}; | ||
let routingInfo; | ||
let routingInfo, request; | ||
const handleError = function (e) { | ||
context.done(e); | ||
}; | ||
context.callbackWaitsForEmptyEventLoop = false; | ||
return executeInterceptor(request, context).then(function (modifiedRequest) { | ||
if (!modifiedRequest) { | ||
return context.done(null, null); | ||
} else if (isApiResponse(modifiedRequest)) { | ||
return context.done(null, packResult(modifiedRequest, getRequestRoutingInfo(request), {}, 'success')); | ||
} else { | ||
routingInfo = getRequestRoutingInfo(modifiedRequest); | ||
if (routingInfo && routingInfo.path && routingInfo.method) { | ||
return routeEvent(routingInfo, modifiedRequest, context, callback).then(function (result) { | ||
context.done(null, result); | ||
}); | ||
try { | ||
request = getRequest(event, context); | ||
} catch (e) { | ||
return Promise.resolve().then(() => context.done(null, { | ||
statusCode: 500, | ||
headers: { 'Content-Type': 'text/plain' }, | ||
body: (e && e.message) || 'Invalid request' | ||
})); | ||
} | ||
return executeInterceptor(request, context) | ||
.then(modifiedRequest => { | ||
if (!modifiedRequest) { | ||
return context.done(null, null); | ||
} else if (isApiResponse(modifiedRequest)) { | ||
return context.done(null, packResult(modifiedRequest, getRequestRoutingInfo(request), {}, 'success')); | ||
} else { | ||
if (unsupportedEventCallback) { | ||
unsupportedEventCallback(event, context, callback); | ||
routingInfo = getRequestRoutingInfo(modifiedRequest); | ||
if (routingInfo && routingInfo.path && routingInfo.method) { | ||
return routeEvent(routingInfo, modifiedRequest, context, callback) | ||
.then(result => context.done(null, result)); | ||
} else { | ||
return Promise.reject('event does not contain routing information'); | ||
if (unsupportedEventCallback) { | ||
unsupportedEventCallback(event, context, callback); | ||
} else { | ||
return Promise.reject('event does not contain routing information'); | ||
} | ||
} | ||
} | ||
} | ||
}).catch(handleError); | ||
}).catch(handleError); | ||
}; | ||
@@ -377,3 +392,3 @@ self.router = function (event, context, callback) { | ||
if (postDeploySteps[name]) { | ||
throw new Error('Post deploy hook "' + name + '" already exists'); | ||
throw new Error(`Post deploy hook "${name}" already exists`); | ||
} | ||
@@ -383,3 +398,3 @@ postDeploySteps[name] = stepFunction; | ||
self.addPostDeployConfig = function (stageVarName, prompt, configOption) { | ||
self.addPostDeployStep(stageVarName, function (options, lambdaDetails, utils) { | ||
self.addPostDeployStep(stageVarName, (options, lambdaDetails, utils) => { | ||
const configureDeployment = function (varValue) { | ||
@@ -395,5 +410,4 @@ const result = { | ||
deployStageVar = function (deployment) { | ||
return utils.apiGatewayPromise.createDeploymentPromise(deployment).then(function () { | ||
return deployment.variables[stageVarName]; | ||
}); | ||
return utils.apiGatewayPromise.createDeploymentPromise(deployment) | ||
.then(() => deployment.variables[stageVarName]); | ||
}, | ||
@@ -418,7 +432,5 @@ getVariable = function () { | ||
executeStepMapper = function (stepName) { | ||
return utils.Promise.resolve().then(function () { | ||
return postDeploySteps[stepName](options, lambdaDetails, utils); | ||
}).then(function (result) { | ||
stepResults[stepName] = result; | ||
}); | ||
return utils.Promise.resolve() | ||
.then(() => postDeploySteps[stepName](options, lambdaDetails, utils)) | ||
.then(result => stepResults[stepName] = result); | ||
}; | ||
@@ -428,5 +440,4 @@ if (!steps.length) { | ||
} | ||
return utils.Promise.map(steps, executeStepMapper, {concurrency: 1}).then(function () { | ||
return stepResults; | ||
}); | ||
return utils.Promise.map(steps, executeStepMapper, {concurrency: 1}) | ||
.then(() => stepResults); | ||
}; | ||
@@ -438,3 +449,3 @@ self.registerAuthorizer = function (name, config) { | ||
if (!config || typeof config !== 'object' || Object.keys(config).length === 0) { | ||
throw new Error('Authorizer ' + name + ' configuration is invalid'); | ||
throw new Error(`Authorizer ${name} configuration is invalid`); | ||
} | ||
@@ -445,3 +456,3 @@ if (!authorizers) { | ||
if (authorizers[name]) { | ||
throw new Error('Authorizer ' + name + ' is already defined'); | ||
throw new Error(`Authorizer ${name} is already defined`); | ||
} | ||
@@ -456,3 +467,2 @@ authorizers[name] = config; | ||
['ANY'].concat(supportedMethods).forEach(setUpHandler); | ||
}; |
@@ -6,3 +6,3 @@ /*global require, module, process */ | ||
'use strict'; | ||
return new PromiseImpl(function (resolve, reject) { | ||
return new PromiseImpl((resolve, reject) => { | ||
const rl = readline.createInterface({ | ||
@@ -12,3 +12,3 @@ input: process.stdin, | ||
}); | ||
rl.question(question + ' ', function (answer) { | ||
rl.question(`${question} `, answer => { | ||
rl.close(); | ||
@@ -18,3 +18,3 @@ if (answer) { | ||
} else { | ||
reject(question + ' must be provided'); | ||
reject(`${question} must be provided`); | ||
} | ||
@@ -21,0 +21,0 @@ }); |
@@ -14,5 +14,3 @@ /*global module, require */ | ||
'use strict'; | ||
Object.keys(keyMappings).forEach(function (key) { | ||
to[key] = from[keyMappings[key]] || {}; | ||
}); | ||
Object.keys(keyMappings).forEach(key => to[key] = from[keyMappings[key]] || {}); | ||
}, | ||
@@ -40,3 +38,2 @@ convertContext = function (requestContext) { | ||
}; | ||
}, | ||
@@ -77,3 +74,3 @@ getConvertedBody = function (body, contentType, isBase64Encoded) { | ||
if (canonicalContentType === 'application/x-www-form-urlencoded') { | ||
result.post = qs.parse(convertedBody); | ||
result.post = Object.assign({}, qs.parse(convertedBody)); | ||
} | ||
@@ -83,3 +80,7 @@ if (canonicalContentType === 'application/json' && | ||
) { | ||
result.body = JSON.parse(convertedBody || '{}'); | ||
try { | ||
result.body = JSON.parse(convertedBody || '{}'); | ||
} catch (e) { | ||
throw new Error('The content does not match the supplied content type'); | ||
} | ||
} else { | ||
@@ -86,0 +87,0 @@ result.body = convertedBody; |
@@ -6,7 +6,5 @@ /*global module */ | ||
if (object && typeof object === 'object' && !Array.isArray(object)) { | ||
Object.keys(object).forEach(function (key) { | ||
result[key.toLowerCase()] = object[key]; | ||
}); | ||
Object.keys(object).forEach(key => result[key.toLowerCase()] = object[key]); | ||
} | ||
return result; | ||
}; |
26328
569