{"id":25170208,"url":"https://github.com/chocpanda/mambda","last_synced_at":"2025-10-24T07:30:27.344Z","repository":{"id":34897780,"uuid":"185159333","full_name":"ChocPanda/mambda","owner":"ChocPanda","description":"A Middleware and lifecycle framework for build AWS Lambdas","archived":false,"fork":false,"pushed_at":"2022-01-15T04:11:30.000Z","size":1401,"stargazers_count":5,"open_issues_count":11,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-08-08T19:16:09.777Z","etag":null,"topics":["aws","aws-lambda","faas","faas-framework","javascript","node-js","nodejs"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ChocPanda.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-05-06T08:51:57.000Z","updated_at":"2024-01-13T23:59:52.000Z","dependencies_parsed_at":"2022-08-08T02:15:49.884Z","dependency_job_id":null,"html_url":"https://github.com/ChocPanda/mambda","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChocPanda%2Fmambda","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChocPanda%2Fmambda/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChocPanda%2Fmambda/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChocPanda%2Fmambda/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ChocPanda","download_url":"https://codeload.github.com/ChocPanda/mambda/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237926579,"owners_count":19388577,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","aws-lambda","faas","faas-framework","javascript","node-js","nodejs"],"created_at":"2025-02-09T08:39:59.643Z","updated_at":"2025-10-24T07:30:22.003Z","avatar_url":"https://github.com/ChocPanda.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MAMBDA\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://circleci.com/gh/ChocPanda/mambda\" alt=\"CircleCI\"\u003e\n    \u003cimg src=\"https://img.shields.io/circleci/project/github/ChocPanda/mambda/master.svg?style=popout\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://codecov.io/gh/ChocPanda/mambda\" alt=\"codecov\"\u003e\n    \u003cimg src=\"https://codecov.io/gh/ChocPanda/mambda/branch/master/graph/badge.svg\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://app.codacy.com/app/ChocPanda/mambda?utm_source=github.com\u0026utm_medium=referral\u0026utm_content=ChocPanda/mambda\u0026utm_campaign=Badge_Grade_Dashboard\" alt=\"Codacy Badge\"\u003e\n    \u003cimg src=\"https://api.codacy.com/project/badge/Grade/eb560d0d91a542d3b4ff913e1b94789c\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://david-dm.org/ChocPanda/mambda\" alt=\"dependencies\"\u003e\n    \u003cimg src=\"https://david-dm.org/ChocPanda/mambda.svg\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/mambda\" alt=\"npm\"\u003e\n    \u003cimg alt=\"npm\" src=\"https://img.shields.io/npm/v/mambda.svg?label=npm%40latest\u0026style=popout\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/ChocPanda/mambda/blob/master/LICENSE\" alt=\"license\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/license/ChocPanda/mambda.svg?style=popout\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/xojs/xo\" alt=\"XO code style\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/code_style-XO-5ed9c7.svg\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"http://commitizen.github.io/cz-cli/\" alt=\"Commitizen friendly\" \u003e\n    \u003cimg src=\"https://img.shields.io/badge/commitizen-friendly-brightgreen.svg\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/semantic-release/semantic-release\" alt=\"semantic-release\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://greenkeeper.io/\" alt=\"Greenkeeper badge\" \u003e\n    \u003cimg src=\"https://badges.greenkeeper.io/ChocPanda/mambda.svg\"/\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\nA middleware and lifecycle framework for building service functions in AWS lambda functions.\n\n## Inspiration\n\nThis project was inspired by [middy js](https://github.com/middyjs/middy), `a stylish library with some excellent tooling for building service functions`. The project has taken a few of those ideas and attempts to apply a more [functional programming style](https://codeburst.io/functional-programming-in-javascript-e57e7e28c0e5) to their implementation. The project was originally created and started at [aws-middleware-js](https://github.com/ChocPanda/aws-middleware-js)\n\n## Contents\n\n\u003c!--  toc --\u003e\n\n- [MAMBDA](#mambda)\n\t- [Inspiration](#inspiration)\n\t- [Contents](#contents)\n\t- [Installation](#installation)\n\t\t- [Usage](#usage)\n\t\t\t- [Simple example using callbacks](#simple-example-using-callbacks)\n\t\t\t- [Promises](#promises)\n\t\t\t- [Middlewares](#middlewares)\n\t\t- [Lifecycle additions](#lifecycle-additions)\n\t\t- [Logging](#logging)\n\t\t\t- [Logging API](#logging-api)\n\t- [Middleware](#middleware)\n\t\t- [Custom Middlewares](#custom-middlewares)\n\t- [Why](#why)\n\t\t- [Take advantage of Execution Context reuse](#take-advantage-of-execution-context-reuse)\n\t\t- [Reduce boilerplate for writing lambda functions](#reduce-boilerplate-for-writing-lambda-functions)\n\t- [References](#references)\n\t- [Notes](#notes)\n\t- [Contributions](#contributions)\n\t\t- [Conventional Commits](#conventional-commits)\n\n\u003c!--  tocstop --\u003e\n\n## Installation\n\n-   Install using yarn:\n    `yarn add mambda`\n\n-   Install using npm:\n    `npm install mambda`\n\n### Usage\n\nmambda fits seemlessly into the [programming model](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html) for writing AWS lambdas\n\n#### Simple example using callbacks\n\n```javascript\nconst lambda = require('mambda')\n\nfunction myHandler(event, context, callback) {\n  //... function code\n  callback(null, \"some success message\");\n  // or\n  // callback(\"some error type\");\n}\n\nexports.handler = lambda(myHandler)\n```\n\n#### Promises\n\nYou can also use promises directly\n\n```javascript\nconst lambda = require('mambda')\n\nfunction myAsyncHandler(event, context, callback) {\n  //... function code\n  const promise = foo(); // Some asynchronously executed code\n  return promise\n    .then(resultOfFoo =\u003e process(resultOfFoo))\n    .catch(err =\u003e {\n      console.log('Naughty error', err)\n      return { statusCode: 500, body: 'An error occurred during execution' };\n    })\n}\n\nexports.handler = lambda(myAsyncHandler)\n```\n\nand use async/await syntax\n\n```javascript\nconst lambda = require('mambda')\n\nasync function myAsyncHandler(event, context, callback) {\n  //... function code\n  const foo = await bar(); // Some asynchronously executed code\n  return someOperation(foo);\n}\n\nexports.handler = lambda(myAsyncHandler)\n```\n\n#### Middlewares\n\nThe value of using the middlewares is that they encapsulate a composable, configurable API for isolating and your wrapping business logic in common boiler plate that would otherwise be cluttering your code base.\n\n```javascript\nconst lambda = require('mambda');\nconst jsonBodyParser = require('mambda/middlewares/json-body-parser');\nconst httpErrorHandler = require('mambda/middlewares/http-error-handler');\n\nasync function myAsyncHandler(event, context, callback) {\n  // All of this commented boiler-plate is made unnecessary simply by adding the the jsonBodyParser middleware and error handling middleware\n  // try {\n  //   const body = headers['Content-Type'] === 'application/json')\n  //     ? JSON.parse(event.body)\n  //     : {}\n  // } catch (error) {\n  //   other error handling...\n  //   return { statusCode: 422, body: 'Unprocessable entity, invalid json in request body' }\n  // }\n\n  const body = event.body;   // A javascript object from the deserialized json in the original event\n  const foo = await bar();\n  //... function code\n  return someOperation(foo);\n}\n\nexports.handler = lambda(myAsyncHandler)\n  .use(jsonBodyParser())\n  .use(httpErrorHandler())\n```\n\n### Lifecycle additions\n\nMambda adds an initialisation step to the lambda function, mambda lazily evaluates the resource and caches the result for [reuse of the execution environment](https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html).\n\n![Lifecycle diagram](img/lifecycle.svg)\n\nThe lazy evaluation makes mocking/stubbing shared resources much easier for unit testing with frameworks/libraries such as [jest](https://jestjs.io/docs/en/mock-functions#mocking-modules), [sinon](https://sinonjs.org/releases/v7.3.2/mocks/), [simple-mock](https://github.com/jupiter/simple-mock#mock), etc...\n\nCaching allows users to make full use and reuse of the [lambda execution context](https://docs.aws.amazon.com/lambda/latest/dg/running-lambda-code.html)\n\n```javascript\nconst lambda = require('mambda');\nconst AWS = require('aws-sdk')\n\nconst myHandler = s3 =\u003e (event, context, callback) =\u003e {\n\n  var params = { Bucket: process.env.BUCKET_NAME, Key: process.env.BUCKET_KEY, Body: process.env.BODY };\n  \n  // function code...\n  s3.putObject(params, function(err, data) {\n    if (err) {\n      callback(err)\n    } else {\n      callback(null, 'Put the body into the bucket! YAY!')\n    }\n  });\n  \n}\n\nexports.handler = lambda({ init: () =\u003e new AWS.S3(), handler: myHandler });\n```\n\n### Logging\n\nThe LambdaFunc configuration object also accepts a logger parameter that will log progress and other helpful debug information. The logger need only expose **info**, **debug**, **warn**, **error** and **trace** functions of a similar signature to the built in [console logger](https://nodejs.org/api/console.html) making it compatible with other loggers such as [pinojs](https://github.com/pinojs/pino), [winstonjs](https://github.com/winstonjs/winston) or [signale](https://github.com/klaussinani/signale)\n\n#### Logging API\n\nUsing console logging\n\n```javascript\nconst lambda = require('mambda');\n\nexports.handler = lambda({\n  logger: console,\n  handler: (event, context, callback) =\u003e {\n    // function code...\n  }\n});\n```\n\nBut the console could be replaced with... [pinojs](https://github.com/pinojs/pino) (Or any other logger with a similar API)\n\n```javascript\nconst lambda = require('mambda');\nconst pino = require('pino')();\n\nexports.handler = lambda({\n  logger: pino,\n  handler: (event, context, callback) =\u003e {\n    // function code...\n  }\n});\n```\n\n_The logger must be set to be used._\n\n## Middleware\n\n-   [JSON Body Parser](./src/middlewares/json-body-parser/README.md)\n-   [Http Error Handling](./src/middlewares/http-error-handler/README.md)\n-   [Http Header Normalizer](./src/middlewares/http-error-handler/README.md)\n-   _Content Negotiation_ - [Coming soon...](https://github.com/ChocPanda/mambda/issues/4)\n-   _Http Query Parser_ - [Coming soon...](https://github.com/ChocPanda/mambda/issues/5)\n-   [...Your idea here](https://github.com/ChocPanda/mambda/issues/new)\n\n### Custom Middlewares\n\nCan't find quite what you're looking for? Why not [consider contributing...](./CONTRIBUTING.md), [raising a feature request](https://github.com/ChocPanda/mambda/issues/new?assignees=\u0026labels=\u0026template=feature_request.md\u0026title=) or upvoting an [existing one](https://github.com/ChocPanda/mambda/issues) it would be much appreciated and is really helpful in prioritisation, but if you're in a hurry here's how to create custom middleware.\n\nThe middlewares are all simple javascript objects with **atleast 1** of the following 3 functions:\n\n-   **before**: A function called before the handler, used to update/add to the lambda event or context\n\n```javascript\n/**\n * @param {AWSLambdaEvent} event aws event triggering the lambda\n * @param {AWSLambdaContext} context aws runtime/execution context\n * @returns {(Array|AWSLambdaEvent|undefined)}\n * \t\t-  An array with 2 elements [newEvent {AWSLambdaEvent}, newContext {AWSLambdaContext}]\n * \t\t-  A new AWSLambdaEvent\n * \t\t- {undefined} if the middleware had no changes to make to the event/context\n */\nfunction before(event, context) { // ...function code\n```\n\n-   **after**: A function called after the handler, used to update/add to the lambda response\n\n```javascript\n/**\n * @param {AWSLambdaResponse} result the result of having called the lambda function with the given event and context\n * @param {AWSLambdaEvent} event aws event that triggered the lambda\n * @param {AWSLambdaContext} context aws runtime/execution context\n * @returns {(Array|AWSLambdaResponse|undefined)}\n *\t-  An array with 2 elements [newEvent {AWSLambdaResponse}, newContext {AWSLambdaContext}]\n *\t-  A new AWSLambdaResponse\n *\t- {undefined} if the middleware had no changes to make to the event/context\n */\nfunction after(result, event, context) { // ...function code\n```\n\n-   **onError**: A function called in the event the handler or another middleware should throw an exception, used to create a response from the lambda\n\n```javascript\n/**\n * @param {AWSLambdaResponse} result the accumulated response of other error handling middlewares\n * @param {Error} error the error that was thrown either by a preceeding middleware or the lambda function\n * @param {AWSLambdaEvent} event aws event that triggered the lambda prior to the exception being thrown\n * @param {AWSLambdaContext} context aws runtime/execution context\n * @returns {(Array|AWSLambdaResponse|undefined)}\n *\t-  An array with 2 elements [new result {AWSLambdaResponse}, new Error {Error}]\n *\t-  A new result {AWSLambdaResponse}\n *\t- {undefined} if the middleware had no changes to make to the event/context\n */\nfunction onError(result, error, event, context) { // ...function code\n```\n\nDocumentation detailing the contents of:\n\n-   [AWSLambdaEvent](https://docs.aws.amazon.com/lambda/latest/dg/lambda-services.html) (Depends on the trigger)\n-   e.g.: [API Gateway](https://docs.aws.amazon.com/apigateway/latest/developerguide/request-response-data-mappings.html#mapping-request-parameters)\n-   [AWSLambdaContext](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html)\n-   AWSLambdaResponse (Depends on the trigger)\n-   e.g.: [API Gateway](https://docs.aws.amazon.com/apigateway/latest/developerguide/request-response-data-mappings.html#mapping-response-parameters)\n-   Error\n-   Currently all errors thrown by built in middlewares will be [http-errors](https://github.com/jshttp/http-errors). This is because API gateway is a common trigger for lambdas and the existing middlewares are most useful behind API Gateway. Please [report any non-http-errors](https://github.com/ChocPanda/mambda/issues/new?assignees=\u0026labels=\u0026template=bug_report.md\u0026title=) thrown by any built-in middlewares.\n\n```javascript\nconst myCustomMiddleware = (middlewareConfig) =\u003e ({\n  before: (event, context) =\u003e { /* function code... */ },\n  after: (result, event, context) =\u003e { /* function code... */ },\n  onError: (error, event, context) =\u003e { /* function code... */ }\n});\n```\n\nOnce created there is no special transformation or class, just... [use it as you would any other middleware](#api)\n\n```javascript\nexport.handler = lambdaFunc(handler).use(myCustomMiddleware(myMiddlewareConfig))\n```\n\nAll of the middlewares function can be either synchronous or asynchronous, it's up to you and your use case.\n\n## Why\n\n### Take advantage of Execution Context reuse\n\n  This is pretty simple to do and Amazon provide a number of examples of code that does exactly that where the coding samples will initialise global/static variables outside of the scope of handler function so that if the execution context is reused they are already initialised and the recycled environment is more performant than when the lambda function is executed from a cold start.\n\n  The problem with these examples is that the shared resources are often initialised as a side effect of simply loading the javascript file into memory (fairly poor practice when writing modular code), it makes the service functions more difficult to test because it is difficult to mock or provide stub dependencies. This middleware library provides a lifecycle which supports enables mocking dependencies and encourages developers to write pure javascript files free from side effects.\n\n### Reduce boilerplate for writing lambda functions\n\n  When writing lambdas there can be a fair bit of boiler plate code wrapping up the business logic and cluttering your code base, AWS middleware abstracts this out into common reusable middlewares that can be configured and shared across all your lambdas\n\n## References\n\n-   [AWS Lambda functions](https://aws.amazon.com/lambda/)\n-   [Best Practices guide](https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-code).\n\n## Notes\n\nA key factor here is that the lambdaFunc will respect how you want to write AWS lambdas:\n\n-   if you want to return a promise, lambda-func will return a promise\n-   if you want to use callbacks, lambda-func call the callback\n\nAlways while wrapping up your code in the middlewares you've chosen with no extra work.\n\nThis library is designed and written to be as small and lightweight as possible ([a nano library if you will](https://medium.com/@kelin2025/writing-js-libraries-less-than-1tb-size-6342da0c006a)). Therefore I won't include any dependencies in here specific to just a single middleware however if it's useful I will try to create and maintain seperate intergrations with other libraries.\n\n## Contributions\n\nSee our [contributing doc](./CONTRIBUTING.md), be sure to checkout the [code of conduct](./CONTRIBUTING.md#code-of-conduct)\n\n### Conventional Commits\n\nThis project used [conventional commits](https://www.conventionalcommits.org/en/v1.0.0-beta.3/#specification) to manage versions and releases of the library therefore when making a commit please use `yarn commit \u003cCOMMIT_PARAMETERS\u003e` and this will guide you through writing a conventional commit message which can be understood work with the ci pipeline\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchocpanda%2Fmambda","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchocpanda%2Fmambda","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchocpanda%2Fmambda/lists"}