@compeon/lambda-helpers
v0.5.0
Published
helper functions for lambdas
Downloads
14
Readme
COMPEON Lambda Helpers
Useful functions that will probably be used across all Lambda functions. Mainly by using the wrapper compeonHandler
and log
.
Note: Type definitions in this README are meant as a help and do not strictly follow TypeScript or Flow conventions.
compeonHandler
compeonHandler(
handler: func,
middleware?: func[]
): Promise<AWS response>`
params:
handler: (event, context, callback) => { body, statusCode, headers }
middleware: ({ event, context, callback }) => ({ body, statusCode, headers })
The main function of this package. It...
- expects an event handler, sync or async
- passes your result to the AWS
lambda_handler
- catches and logs (see
log
) errors thrown inside your event handler - accepts
middleware
to modify incoming parameters and outgoing responses alike (note the single object with keysevent
,context
, andcallback
)
Note: requires Node 8.10 or above
Example:
exports.lambda_handler = compeonHandler(event =>
const { testString } = event.queryStringParameters
// the following gets caught and logged
if (!testString) throw new CompeonError('I need a test string', 422)
// this works as well, but error stack would be missing:
if (!testString) throw 'I need a test string'
// the following gets returned as promise
return {
body: 'my result'
}
)
The response, in error case, would be:
{
"body": {
"errors": [{
"code": "Unprocessible Entity",
"detail": "I need a testString",
"status": 422,
"title": "422 (Unprocessable Entity)"
}]
},
"statusCode": 422,
}
Note that this example uses the CompeonError
(see CompeonError
) to set a status.
CompeonError
Error class that allows saving status
(as well as the message).
Example
if (errorCondition) throw new CompeonError('I need a test string', 422)
If thrown inside a compeonHandler
, the error gets logged and passed as the lambda's response. Note that error responses, just like normal ones, pass through the outputMiddleware (see using middleware
).
using middleware
The compeonHandler
accepts an array of middleware functions as an optional second parameter.
A middleware needs to adhere to the following structure
const middleware = next => async ({ event, context, callback }) => {
// Do something with inputs.
// Call next middleware. As the lambda handler is async, any middleware
// that deals with a response must be async as well.
const response = await next({ event, context, callback })
// Do something with the response.
// Pass response to the preceding middleware or, if the last one, back to AWS.
return response
}
ready-to-use middleware
This package provides some useful outputMiddleware for convenience.
awsResponseMiddleware
Transforms any object to an AWS response by wrapping your result into the key body
.
Example:
exports.lambda_handler = compeonHandler(
// your handler
event => ({ test: event.inputKey, resultKey: 'resultValue' }),
[
awsResponseMiddleware,
// add a in inputMiddleware for demonstration purposes
next => ({ event }) => ({ event: { inputKey: 'from inputMiddleware' } })
]
)
This would result in the following response:
{
"body": {
"test": "from inputMiddleware",
"resultKey": "resultValue"
},
"statusCode": 200
}
corsMiddleware
Factory function for a middleware that answers early to OPTIONS requests and adds CORS headers to responses.
Example:
const cors = corsMiddleware({
// Must be true if the middleware is used in a CloudFront lambda.
// Default is false.
cloudFront: false,
// Custom headers to be added to response.
customHeaders: { 'Access-Control-Allow-Headers': 'authorization, content-type, content-disposition' },
// Whitelisted HTTP methods.
// Default is [].
methods: ['OPTIONS', 'POST', 'PUT'],
// Whitelisted origins.
// Default is [].
origins: ['http://localhost:3001', 'http://localhost:3002']
})
exports.lambda_handler = compeonHandler(event => { ... }, [cors])
To allow (= mirror) all origins, add '**'
to the origin whitelist. This precedes any other whitelist configuration.
caseTransformationMiddleware
Factory function for a middleware that camelcases the event body of the request and dasherizes the response body.
Example:
exports.lambda_handler = compeonHandler(
// Your handler
event => ({ resultKey: `${event.resultKey} ABC` })
// Camelcase input and dasherize output
[caseTransformationMiddleware(), awsResponseMiddleware],
)
Given the AWS event
{
"body": {
"result-key": "test"
}
}
the response of the lambda would be
{
"body": {
"result-key": "test ABC"
},
"statusCode": 200
}
Options
caseTransformationMiddleware({
// Specifies whether the request body should be camelcased.
// Default is true.
transformRequest,
// Specifies whether the response body should be camelcased.
// Default is true.
transformResponse
})
Logging
This section covers functions for logging functionality.
log
`log(data: any): void`
Log data in a JSON-stringified, formatted way. Use it the same way you would use console.log
, but note that calls with multiple arguments are not supported.
Example:
log(myTestObject)
toJsonString
`toJsonString(data: Object): void`
Just a convenience method. Calls JSON.stringify(data, null, 2)
.
Deep Object transformation
This package also includes three functions to transform object keys: for kebab-case, camelCase, and a generic one with custom transformator.
deepCamelTransform
deepCamelTransform(data: any): any
Deeply transforms object keys of data
to camelCase
keys. Also transforms arrays if they contain any objects.
Example:
deepCamelTransform(
{ PascalCaseKey: 'value', nested_object: { 'kebab-case': 'value' } }
)
// { pascalCaseKey: 'value', nestedObject: { kebabCase: 'value' } }
deepKebabTransform
deepKebabTransform(data: any): any
Same as deepCamelTransform
, but with kebab-case
:
Example:
deepKebabTransform(
{ PascalCaseKey: 'value', nested_object: { 'kebab-case': 'value' } }
)
// { "pascal-case-key": 'value', "nested-object": { "kebab-case": 'value' } }
deepKeyTransformer
deepKeyTransformer(transformFunc: (string) => (string)): (Array|Object) => (Array|Object)
Creates a deepKeyTransformer with the given transformer. Example:
deepKeyTransformer(kebabCase)
// returns a function equal to deepKebabTransform
responses
The following functions turn some input into AWS Lambda responses of the form:
{
"body": someBody,
"statusCode": number,
"headers": optionalHeaders
}
Transforms that can directly be used on axios responses are provided as well.
handleAxiosError
handleAxiosError(axiosResponse: Object): Object
Mostly used inside catch
of an axios
request. Extracts error from the response and calls handleError
with it.
Note: Will only work with responses that follow the structure of an axios
response.
Example:
axios.get(apiUrl)
.then(someResponseHandler)
.catch(handleAxiosError)
handleAxiosOk
handleAxiosOk(body: Object): Object
Can be used to chain the data of an axios request directly as the Lambda response. Expects a data
attribute
exports.lambda_handler = (event) => {
return axios.get('https://jsonplaceholder.typicode.com/todos/1')
.then(handleAxiosOk)
}
// the lambda returns {"userId":1,"id":1,"title":"delectus aut autem","completed":false}
handleEmptyOk
handleEmptyOk(): Object
If an empty 200 response is wanted (Still contains the string 'ok').
exports.lambda_handler = (event) => {
// omitted ...
return axios.get(apiUrl)
.then(someResponseHandler) // Can provide anything, handleEmptyOk has no expectations
.then(handleEmptyOk)
}
handleError
handleError(error: any, status?: number): Object
Used to log the provided error to cloudwatch. Returns AWS Lambda conform response object. If error
is not a string, it gets JSON-stringified.
status
defaults to 500.
Example:
handleError('not found', 404)
// => logs 'not found' to cloudwatch console
// => { body: 'not found', statusCode: 404 }
handleOk
handleOk(body?: string|object, headers?: object, statusCode?: number): Object
Returns an AWS Lambda conform response object with the preferred body. statusCode
defaults to 200
. Can be used to chain a previous response to the Lambda output.
Example:
handleOk()
// => { "body": "ok", "statusCode": 200 }
// May also be used as a last handler in a promise chain to directly transform the previous' handlers response as the response of the Lambda itself:
exports.lambda_handler = (event) => {
return axios.get(apiUrl)
.then(someResponseHandler) // => Must provide json-parsable object
.then(handleOk)
}
handleRedirect
handleRedirect(url: string, statusCode?: 302): Object
Can be used to quickly generate HTTP redirections. Example:
handleRedirect('www.example.com')
// => { "headers": { "Location": "www.example.com" }, "statusCode": 322 }