Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Router: CloudFormation Custom Resource #1268

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
46 changes: 46 additions & 0 deletions packages/cloudformation-response/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<div align="center">
<h1>Middy cloudformation lambda middleware</h1>
<img alt="Middy logo" src="https://raw.githubusercontent.com/middyjs/middy/main/docs/img/middy-logo.svg"/>
<p><strong>CloudFormation Custom Response event response handling for the middy framework, the stylish Node.js middleware engine for AWS Lambda</strong></p>
<p>
<a href="https://www.npmjs.com/package/@middy/cloudformation-response?activeTab=versions">
<img src="https://badge.fury.io/js/%40middy%cloudformation-response.svg" alt="npm version" style="max-width:100%;">
</a>
<a href="https://packagephobia.com/result?p=@middy/cloudformation-response">
<img src="https://packagephobia.com/badge?p=@middy/cloudformation-response" alt="npm install size" style="max-width:100%;">
</a>
<a href="https://github.com/middyjs/middy/actions/workflows/tests.yml">
<img src="https://github.com/middyjs/middy/actions/workflows/tests.yml/badge.svg?branch=main&event=push" alt="GitHub Actions CI status badge" style="max-width:100%;">
</a>
<br/>
<a href="https://standardjs.com/">
<img src="https://img.shields.io/badge/code_style-standard-brightgreen.svg" alt="Standard Code Style" style="max-width:100%;">
</a>
<a href="https://snyk.io/test/github/middyjs/middy">
<img src="https://snyk.io/test/github/middyjs/middy/badge.svg" alt="Known Vulnerabilities" data-canonical-src="https://snyk.io/test/github/middyjs/middy" style="max-width:100%;">
</a>
<a href="https://github.com/middyjs/middy/actions/workflows/sast.yml">
<img src="https://github.com/middyjs/middy/actions/workflows/sast.yml/badge.svg
?branch=main&event=push" alt="CodeQL" style="max-width:100%;">
</a>
<a href="https://bestpractices.coreinfrastructure.org/projects/5280">
<img src="https://bestpractices.coreinfrastructure.org/projects/5280/badge" alt="Core Infrastructure Initiative (CII) Best Practices" style="max-width:100%;">
</a>
<br/>
<a href="https://gitter.im/middyjs/Lobby">
<img src="https://badges.gitter.im/gitterHQ/gitter.svg" alt="Chat on Gitter" style="max-width:100%;">
</a>
<a href="https://stackoverflow.com/questions/tagged/middy?sort=Newest&uqlId=35052">
<img src="https://img.shields.io/badge/StackOverflow-[middy]-yellow" alt="Ask questions on StackOverflow" style="max-width:100%;">
</a>
</p>
<p>You can read the documentation at: <a href="https://middy.js.org/docs/middleware/cloudformation-response">https://middy.js.org/docs/middleware/cloudformation-response</a></p>
</div>

## License

Licensed under [MIT License](LICENSE). Copyright (c) 2017-2024 [Luciano Mammino](https://github.com/lmammino), [will Farrell](https://github.com/willfarrell), and the [Middy team](https://github.com/middyjs/middy/graphs/contributors).

<a href="https://app.fossa.io/projects/git%2Bgithub.com%2Fmiddyjs%2Fmiddy?ref=badge_large">
<img src="https://app.fossa.io/api/projects/git%2Bgithub.com%2Fmiddyjs%2Fmiddy.svg?type=large" alt="FOSSA Status" style="max-width:100%;">
</a>
23 changes: 23 additions & 0 deletions packages/cloudformation-response/__tests__/fuzz.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { test } from 'node:test'
import fc from 'fast-check'
import middy from '../../core/index.js'
import middleware from '../index.js'

const handler = middy((event) => event).use(middleware({}))
Fixed Show fixed Hide fixed
const context = {
getRemainingTimeInMillis: () => 1000
}

test('fuzz `event` w/ `object`', async () => {
fc.assert(
fc.asyncProperty(fc.object(), async (event) => {
await handler(event, context)
}),
{
numRuns: 100_000,
verbose: 2,

examples: []
}
)
})
88 changes: 88 additions & 0 deletions packages/cloudformation-response/__tests__/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { test } from 'node:test'
import { deepEqual } from 'node:assert/strict'

import middy from '../../core/index.js'

import cloudformationResponse from '../index.js'

const defaultEvent = {
RequestType: 'Create',
RequestId: 'RequestId',
LogicalResourceId: 'LogicalResourceId',
StackId: 'StackId'
}
const context = {
getRemainingTimeInMillis: () => 1000
}

test('It should return SUCCESS when empty response', async (t) => {
const handler = middy((event, context) => {})

handler.use(cloudformationResponse({}))
Fixed Show fixed Hide fixed

const event = defaultEvent
const response = await handler(event, context)
deepEqual(response, {
Status: 'SUCCESS',
RequestId: 'RequestId',
LogicalResourceId: 'LogicalResourceId',
StackId: 'StackId'
})
})

test('It should return SUCCESS when empty object', async (t) => {
const handler = middy((event, context) => {
return {}
})

handler.use(cloudformationResponse({}))
Fixed Show fixed Hide fixed

const event = defaultEvent
const response = await handler(event, context)
deepEqual(response, {
Status: 'SUCCESS',
RequestId: 'RequestId',
LogicalResourceId: 'LogicalResourceId',
StackId: 'StackId'
})
})

test('It should return FAILURE when error thrown', async (t) => {
const handler = middy((event, context) => {
throw new Error('Internal Error')
})

handler.use(cloudformationResponse({}))
Fixed Show fixed Hide fixed

const event = defaultEvent
const response = await handler(event, context)
deepEqual(response, {
Status: 'FAILED',
Reason: 'Internal Error',
RequestId: 'RequestId',
LogicalResourceId: 'LogicalResourceId',
StackId: 'StackId'
})
})

test('It should not override response values', async (t) => {
const handler = middy((event, context) => {
return {
Status: 'FAILED',
RequestId: 'RequestId*',
LogicalResourceId: 'LogicalResourceId*',
StackId: 'StackId*'
}
})

handler.use(cloudformationResponse({}))
Fixed Show fixed Hide fixed

const event = defaultEvent
const response = await handler(event, context)
deepEqual(response, {
Status: 'FAILED',
RequestId: 'RequestId*',
LogicalResourceId: 'LogicalResourceId*',
StackId: 'StackId*'
})
})
25 changes: 25 additions & 0 deletions packages/cloudformation-response/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const cloudformationCustomResourceMiddleware = () => {
const cloudformationCustomResourceMiddlewareAfter = (request) => {
let { response } = request
response ??= {}
response.Status ??= 'SUCCESS'
response.RequestId ??= request.event.RequestId
response.LogicalResourceId ??= request.event.LogicalResourceId
response.StackId ??= request.event.StackId
request.response = response
}
const cloudformationCustomResourceMiddlewareOnError = (request) => {
const response = {
Status: 'FAILED',
Reason: request.error.message
}
request.response = response
cloudformationCustomResourceMiddlewareAfter(request)
}
return {
after: cloudformationCustomResourceMiddlewareAfter,
onError: cloudformationCustomResourceMiddlewareOnError
}
}

export default cloudformationCustomResourceMiddleware
69 changes: 69 additions & 0 deletions packages/cloudformation-response/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
"name": "@middy/cloudformation-response",
"version": "6.0.0",
"description": "CloudFormation Custom Response event response handling for the middy framework",
"type": "module",
"engines": {
"node": ">=20"
},
"engineStrict": true,
"publishConfig": {
"access": "public"
},
"module": "./index.js",
"exports": {
".": {
"import": {
"types": "./index.d.ts",
"default": "./index.js"
},
"require": {
"default": "./index.js"
}
}
},
"types": "index.d.ts",
"files": [
"index.js",
"index.d.ts"
],
"scripts": {
"test": "npm run test:unit",
"test:unit": "node --test __tests__/index.js",
"test:benchmark": "node __benchmarks__/index.js"
},
"license": "MIT",
"keywords": [
"Lambda",
"Middleware",
"Serverless",
"Framework",
"AWS",
"AWS Lambda",
"Middy",
"CloudFormation",
"Custom Response"
],
"author": {
"name": "Middy contributors",
"url": "https://github.com/middyjs/middy/graphs/contributors"
},
"repository": {
"type": "git",
"url": "github:middyjs/middy",
"directory": "packages/cloudformation-response"
},
"bugs": {
"url": "https://github.com/middyjs/middy/issues"
},
"homepage": "https://middy.js.org",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/willfarrell"
},
"devDependencies": {
"@middy/core": "6.0.0",
"@types/aws-lambda": "^8.10.100"
},
"gitHead": "7a6c0fbb8ab71d6a2171e678697de9f237568431"
}
46 changes: 46 additions & 0 deletions packages/cloudformation-router/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<div align="center">
<h1>Middy cloudformation-router lambda handler</h1>
<img alt="Middy logo" src="https://raw.githubusercontent.com/middyjs/middy/main/docs/img/middy-logo.svg"/>
<p><strong>CloudFormation Custom Response router for the middy framework, the stylish Node.js middleware engine for AWS Lambda</strong></p>
<p>
<a href="https://www.npmjs.com/package/@middy/cloudformation-router?activeTab=versions">
<img src="https://badge.fury.io/js/%40middy%cloudformation-router.svg" alt="npm version" style="max-width:100%;">
</a>
<a href="https://packagephobia.com/result?p=@middy/cloudformation-router">
<img src="https://packagephobia.com/badge?p=@middy/cloudformation-router" alt="npm install size" style="max-width:100%;">
</a>
<a href="https://github.com/middyjs/middy/actions/workflows/tests.yml">
<img src="https://github.com/middyjs/middy/actions/workflows/tests.yml/badge.svg?branch=main&event=push" alt="GitHub Actions CI status badge" style="max-width:100%;">
</a>
<br/>
<a href="https://standardjs.com/">
<img src="https://img.shields.io/badge/code_style-standard-brightgreen.svg" alt="Standard Code Style" style="max-width:100%;">
</a>
<a href="https://snyk.io/test/github/middyjs/middy">
<img src="https://snyk.io/test/github/middyjs/middy/badge.svg" alt="Known Vulnerabilities" data-canonical-src="https://snyk.io/test/github/middyjs/middy" style="max-width:100%;">
</a>
<a href="https://github.com/middyjs/middy/actions/workflows/sast.yml">
<img src="https://github.com/middyjs/middy/actions/workflows/sast.yml/badge.svg
?branch=main&event=push" alt="CodeQL" style="max-width:100%;">
</a>
<a href="https://bestpractices.coreinfrastructure.org/projects/5280">
<img src="https://bestpractices.coreinfrastructure.org/projects/5280/badge" alt="Core Infrastructure Initiative (CII) Best Practices" style="max-width:100%;">
</a>
<br/>
<a href="https://gitter.im/middyjs/Lobby">
<img src="https://badges.gitter.im/gitterHQ/gitter.svg" alt="Chat on Gitter" style="max-width:100%;">
</a>
<a href="https://stackoverflow.com/questions/tagged/middy?sort=Newest&uqlId=35052">
<img src="https://img.shields.io/badge/StackOverflow-[middy]-yellow" alt="Ask questions on StackOverflow" style="max-width:100%;">
</a>
</p>
<p>You can read the documentation at: <a href="https://middy.js.org/docs/routers/cloudformation-router">https://middy.js.org/docs/routers/cloudformation-router</a></p>
</div>

## License

Licensed under [MIT License](LICENSE). Copyright (c) 2017-2024 [Luciano Mammino](https://github.com/lmammino), [will Farrell](https://github.com/willfarrell), and the [Middy team](https://github.com/middyjs/middy/graphs/contributors).

<a href="https://app.fossa.io/projects/git%2Bgithub.com%2Fmiddyjs%2Fmiddy?ref=badge_large">
<img src="https://app.fossa.io/api/projects/git%2Bgithub.com%2Fmiddyjs%2Fmiddy.svg?type=large" alt="FOSSA Status" style="max-width:100%;">
</a>
55 changes: 55 additions & 0 deletions packages/cloudformation-router/__tests__/fuzz.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { test } from 'node:test'
import fc from 'fast-check'
import middy from '../../core/index.js'
import router from '../index.js'

const handler = middy(router())
const context = {
getRemainingTimeInMillis: () => 1000
}

test('fuzz `event` w/ `object`', async () => {
fc.assert(
fc.asyncProperty(fc.object(), async (event) => {
try {
await handler(event, context)
} catch (e) {
if (e.cause?.package !== '@middy/cloudformation-router') {
throw e
}
}
}),
{
numRuns: 100_000,
verbose: 2,

examples: []
}
)
})

test('fuzz `event` w/ `record`', async () => {
fc.assert(
fc.asyncProperty(
fc.record({
requestContext: fc.record({
routeKey: fc.string()
})
}),
async (event) => {
try {
await handler(event, context)
} catch (e) {
if (e.cause?.package !== '@middy/ws-router') {
throw e
}
}
}
),
{
numRuns: 100_000,
verbose: 2,
examples: [[{ requestContext: { routeKey: 'valueOf' } }]]
}
)
})
Loading
Loading