-
-
Notifications
You must be signed in to change notification settings - Fork 378
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
base: main
Are you sure you want to change the base?
Changes from 4 commits
28d8166
d47badb
371d9a6
1c2eaaa
65280c5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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%2Bgit.luolix.top%2Fmiddyjs%2Fmiddy?ref=badge_large"> | ||
<img src="https://app.fossa.io/api/projects/git%2Bgit.luolix.top%2Fmiddyjs%2Fmiddy.svg?type=large" alt="FOSSA Status" style="max-width:100%;"> | ||
</a> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
const defaults = { | ||
routes: [], | ||
notFoundResponse: ({ requestType }) => { | ||
return { | ||
Status: 'FAILED', | ||
Reason: `Route ${requestType} does not exist. @middy/cloudformation-router` | ||
} | ||
} | ||
} | ||
const cloudformationCustomResourceRouteHandler = (opts = {}) => { | ||
if (Array.isArray(opts)) { | ||
opts = { routes: opts } | ||
} | ||
const { routes, notFoundResponse } = { ...defaults, ...opts } | ||
|
||
const routesStatic = {} | ||
for (const route of routes) { | ||
const { requestType, handler } = route | ||
|
||
// Static | ||
routesStatic[requestType] = handler | ||
} | ||
|
||
return (event, context, abort) => { | ||
const { RequestType: requestType } = event | ||
if (!requestType) { | ||
return notFoundResponse({ requestType }) | ||
} | ||
|
||
// Static | ||
const handler = routesStatic[requestType] | ||
if (typeof handler !== 'undefined') { | ||
const response = handler(event, context, abort) | ||
response.Status ??= 'SUCCESS' | ||
response.RequestId ??= event.RequestId | ||
response.LogicalResourceId ??= event.LogicalResourceId | ||
response.StackId ??= event.StackId | ||
return response | ||
} | ||
Comment on lines
+32
to
+39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be nice if it also reported to the responseUrl, I feel like even though the abstraction is nice, it doesn't really add that much value currently as it's still the responsibility of the developer to correctly handle all errors and respond. The auto reporting implementation is more what I was looking for honestly |
||
|
||
// Not Found | ||
return notFoundResponse({ requestType }) | ||
} | ||
} | ||
|
||
export default cloudformationCustomResourceRouteHandler |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
{ | ||
"name": "@middy/cloudformation-router", | ||
"version": "6.0.0", | ||
"description": "CloudFormation Custom Response event router 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", | ||
"router" | ||
], | ||
"author": { | ||
"name": "Middy contributors", | ||
"url": "https://github.com/middyjs/middy/graphs/contributors" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "github:middyjs/middy", | ||
"directory": "packages/cloudformation-router" | ||
}, | ||
"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" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
--- | ||
title: cloudformation-router | ||
--- | ||
|
||
This handler can route to requests to one of a nested handler based on `requestType` of a CloudFormation Custom Response event. | ||
|
||
## Install | ||
|
||
To install this middleware you can use NPM: | ||
|
||
```bash | ||
npm install --save @middy/cloudformation-router | ||
``` | ||
|
||
## Options | ||
|
||
- `routes` (array[\{routeKey, handler\}]) (required): Array of route objects. | ||
- `routeKey` (string) (required): AWS formatted request type. ie `Create`, `Update`, `Delete` | ||
- `handler` (function) (required): Any `handler(event, context, {signal})` function | ||
- `notFoundHandler` (function): Override default error thrown with your own custom response. Passes in `{requestType}` | ||
|
||
NOTES: | ||
|
||
- Reponse parameters are automatically applied for `Status`, `RequestId`, `LogicalResourceId`, and/or `StackId` when not present. | ||
- Errors should be handled as part of the router middleware stack **or** the lambdaHandler middleware stack. Handled errors in the later will trigger the `after` middleware stack of the former. | ||
- Shared middlewares, connected to the router middleware stack, can only be run before the lambdaHandler middleware stack. | ||
|
||
## Sample usage | ||
|
||
```javascript | ||
import middy from '@middy/core' | ||
import cloudformationRouterHandler from '@middy/cloudformation-router' | ||
import validatorMiddleware from '@middy/validator' | ||
|
||
const createHandler = middy() | ||
.use(validatorMiddleware({eventSchema: {...} })) | ||
.handler((event, context) => { | ||
return { | ||
PhysicalResourceId: '...', | ||
Data:{} | ||
} | ||
}) | ||
|
||
const updateHandler = middy() | ||
.use(validatorMiddleware({eventSchema: {...} })) | ||
.handler((event, context) => { | ||
return { | ||
PhysicalResourceId: '...', | ||
Data: {} | ||
} | ||
}) | ||
|
||
const deleteHandler = middy() | ||
.use(validatorMiddleware({eventSchema: {...} })) | ||
.handler((event, context) => { | ||
return { | ||
PhysicalResourceId: '...' | ||
} | ||
}) | ||
|
||
const routes = [ | ||
{ | ||
requesType: 'Create', | ||
handler: createHandler | ||
}, | ||
{ | ||
requesType: 'Update', | ||
handler: updateHandler | ||
}, | ||
{ | ||
routeKey: 'delete', | ||
willfarrell marked this conversation as resolved.
Show resolved
Hide resolved
|
||
handler: deleteHandler | ||
} | ||
] | ||
|
||
export const handler = middy() | ||
.use(wsResponseMiddleware()) | ||
.handler(cloudformationRouterHandler(routes)) | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would for example expect that here we report to cloudformation that we have a failure, because if we don't do that cloudformation will simply wait x time until it timeouts whilst we already know that we won't be handling the request