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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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>
27 changes: 27 additions & 0 deletions packages/cloudformation-response/__benchmarks__/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Bench } from 'tinybench'
import middy from '../../core/index.js'
import middleware from '../index.js'

const bench = new Bench({ time: 1_000 })

const context = {
getRemainingTimeInMillis: () => 30000
}
const setupHandler = () => {
const baseHandler = () => {}
return middy(baseHandler).use(middleware())
}

const coldHandler = setupHandler()

const event = {}
await bench
.add('without cache', async () => {
try {
await coldHandler(event, context)
} catch (e) {}
})

.run()

console.table(bench.table())
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())
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())

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())

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())

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())

const event = defaultEvent
const response = await handler(event, context)
deepEqual(response, {
Status: 'FAILED',
RequestId: 'RequestId*',
LogicalResourceId: 'LogicalResourceId*',
StackId: 'StackId*'
})
})
5 changes: 5 additions & 0 deletions packages/cloudformation-response/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import middy from '@middy/core'

declare function cloudformationResponse (): middy.MiddlewareObj

export default cloudformationResponse
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
8 changes: 8 additions & 0 deletions packages/cloudformation-response/index.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { expectType } from 'tsd'
import middy from '@middy/core'

import cloudformationResponse from '.'

// use with default options
const middleware = cloudformationResponse()
expectType<middy.MiddlewareObj>(middleware)
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>
Loading
Loading