• Stars
    star
    187
  • Rank 205,237 (Top 5 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created over 4 years ago
  • Updated about 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A 7KB and 0 dependencies AWS Lambda library which supports middleware and easy debug.

Micro AWS Lambda

Intro

  • For Lambda Proxy / Http API mode
  • Written in Typescript
  • Zero runtime dependencies
  • Tiny: 4.7KB after minified
  • Rapid middlewares
    • simple reasoning, just running one by one
    • early exit with throw or return anything
    • pass values among middlewares
  • Return response
    • an object, it will be converted to a Lambda compatible response
    • a customizable httpResponse() / success() (200)
    • a customizable httpError() / badRequest() (400) / internalError() (500)
    • or string, number, boolean
  • Easy debug:
    • Adding debug info to response object
    • console.log event / context

Why do you build this lib

AWS Lambda is making it a flash to creating an API endpoint. But that's just the infrastructure part. It doesn't mean your business logic can be simplified.

  • I need a middleware setup to decouple my business logic without installing a lib that has many dependencies and result in a bigger bundle size as well.
  • I want to deal with a simple interface, where the order is just one by one. I don't want to deal with a mental model where a middleware will be invoked twice for both stages, and handle both the before and after stage in one function.

What problems does it solve

Middleware is for decoupling logic. I learned the value of beforeHooks and afterHooks after adopting Feathers.JS. Which has a beautiful concept of 3 layers for every endpoint, and I found myself start the declarative programming for the backend. No more code for the repeating work. In micro-aws-lambda's context, it is just an array of Middleware.

Let's say a simple return-a-user endpoint, what does it look like when you are using micro-aws-lambda

const handler = lambdas([
  validateRequestBody(GetUserSchema),
  isStillEmployed,
  verifyPaymentStatus,
  justReturnUserObjectDirectlyFromDB,
  removeFieldsFromResponse('password', 'address'),
  combineUserNames,
  transformResponseToClientSideStructure,
]);

Ideally, you can just compose your future lambda without writing any code except for an integration test. The logic will be declarative. Every middleware here can be fully tested and ready to reuse.

Usage

1. Install

npm install micro-aws-lambda

2. Quick start

import { lambdas } from 'micro-aws-lambda';

const handler = lambdas([() => ({ message: 'it works' })]);

// call the API, you will get json response: { message: "it works" }

3. The usage of Typescript

import { lambdas, Middleware, HttpResponse } from 'micro-aws-lambda';

interface Shared {
  user: { id: string; group: string };
}

interface Response {
  isPassing: boolean;
}

const extractUserFromEvent: Middleware<Shared, Response> = async ({
  event,
  shared,
}) => {
  const user = JSON.parse(event.body);

  if (!user) {
    throw HttpResponse.badRequest({ isPassing: false });
  }

  shared.user = user;
};

const parseUserData: Middleware<Shared, Response> = ({ shared }) => {
  if (shared.user.id === 'bad-user-id') {
    throw HttpResponse.badRequest({ isPassing: false });
  }

  return HttpResponse.success({ isPassing: true });
};

export const handler = lambdas([extractUserFromEvent, parseUserData]);

And later on, if there are any lambda handler needs that extractUserFromEvent, you just reuse that piece anywhere you want!

the default Middleware is for APIGatewayProxyHandlerV2 from @types/aws-lambda. If you are using the Lambda Proxy mode, please import MiddlewareLegacy, otherwise,

4. Two minutes master

  • How to control the flow?

    • return anything that is not null or undefined will STOP the execution
    • throw will STOP the execution
    • just return / return null / return undefined will NOT stop the execution, unless it's the last middleware
    • if nothing is returning after invoking the last middleware, an empty object will be returned
    • otherwise, the array of Middleware will just be executed one by one
    • who returns the 1st wins, for example, lambdas([m1, m2]), if m1 is returning something, it will be used as the http response and m2 will not be executed.
  • What can you return

    • a HttpResponse.response()
    • or a HttpResponse.success() (just a HttpResponse.response() with status code set to 200, you can still change it)
    • or an plain object / string / number (which will be auto-wrapped with HttpResponse.success() in the end)
  • What can you throw

    • HttpResponse.error()
    • HttpResponse.badRequest()
    • HttpResponse.unauthorized()
    • HttpResponse.forbidden()
    • HttpResponse.notFound()
    • HttpResponse.methodNotAllowed()
    • HttpResponse.notAcceptable()
    • HttpResponse.conflict()
    • HttpResponse.internalError()
    • HttpResponse.notImplemented()
    • HttpResponse.badGateway()
    • HttpResponse.serviceUnavailable()
    • HttpResponse.gatewayTimeout()
    • HttpResponse.networkAuthenticationRequire()
    • or anything else

Hover over the function will get a tooltip of the status code for this helper, also, you can pass a 2nd parameter to change the statusCode or headers as well

  • How to pass something down the chain,

    • use shared from the parameter
    • attach your value to it: shared.myValue = 123, myValue could be any name
  • Do I have to return something in the middleware

    • No. For example, a validation middleware can only react to the wrong data without returning anything like if (wrong) {throw badRequest()}

5. Actually, you can throw or return anything

  • return a plain object | string | number === (200) response
  • throw a plain object | string | number === (400) response
  • custom status code by adding statusCode property
  • Or use our built-in shortcut, import {HttpResponse} from 'micro-aws-lambda', then HttpResponse.success({body:{message:'wow'}})

6. Config

6.1 addTraceInfoToResponse

It will add debug info into the response object

{
  debug: {
    endpoint: "",
    requestBody: "",
    requestMethod: "",

    country: "",
    lambdaRequestId: "",
    logStreamName: "",
    logGroupName: "",
    apiGatewayId: ""
  }
}

6.2 logRequestInfo

It will console.log:

  • event
  • context
  • Aws-Api-Gateway-Request-Id
  • Identity-Source-Ip

7. Migrating from v4

  • passDownObj has renamed to shared
  • return STOPS the execution now, like throw, makes the flow easier to reason about!
  • all http helpers can be used under HttpResponse, just import this one alone

Credits

  • The initial version is heavily inspired by my favourite REST framework: Feathers.JS
  • This project was bootstrapped with TSDX.

More Repositories

1

auto-zustand-selectors-hook

Enjoy the performance gain of selectors without writing selectors in Zustand.
TypeScript
104
star
2

kotlin-native-mobile-multiplatform-example

Code sharing between iOS and Android with Kotlin native
Swift
52
star
3

modern-es6-npm-boilerplate

An ES6 boilerplate for writing NPM package.
JavaScript
44
star
4

feathers-next-example

Use feathers with next.js
HTML
43
star
5

veasy

A comprehensive react form solution which aims to eliminate all tedious logic.
JavaScript
31
star
6

world-cities-mongodb

A free world cities database
Python
29
star
7

DaggerAndroidKotlinExample

A minimal setup for using dagger-android with Kotlin to setup application wide and activity wide dependencies.
Kotlin
15
star
8

react-oxygen-ui

Building blocks for React app
JavaScript
7
star
9

kotlin-multuplatform-including-mobile

Kotlin
5
star
10

Fungus-QTE-Command

Add an QTE command to fungus games
C#
5
star
11

react-fullstack-boilerplate

React, react-router, redux, redux-saga, babel, webpack, scss, feathers.js, jest, eslint
JavaScript
4
star
12

SOFTENG-750-PROJECT

TypeScript
3
star
13

blog

A backup of my static blog
3
star
14

enhanced-create-react-app

Added new features to create-react-app without ejecting
JavaScript
3
star
15

PermissionK

Opinionated Android permission handling done right with Kotlin.
Kotlin
2
star
16

react-native-actionsheet-helper

The missing wrapper for React Native ActionSheet
TypeScript
2
star
17

micro-azure-functions

A middleware library from decoupling business logic in Microsoft Azure Functions
TypeScript
2
star
18

dynamodb-try

a composite key pattern which can remove 1 nested level
JavaScript
1
star
19

code

JavaScript
1
star
20

kids-math-print

Generate math quiz for your kinds, render in browser and print it
TypeScript
1
star
21

ent-reproduce

Go
1
star
22

react-navigation-test-re-produce

TypeScript
1
star
23

golang-why

Go
1
star
24

test-rhf-with-jest-expo

JavaScript
1
star
25

expo-router-web-try-out

TypeScript
1
star
26

expo-reanimated-example

An example of use renaimated to do some simple animation
TypeScript
1
star
27

JestIssue

JavaScript
1
star
28

React-Modern-Templates

This repo is a setup for a combination of the popular React tech stack. So you can simple clone and ready to go.
TypeScript
1
star
29

my-rxdb-app

TypeScript
1
star
30

D3v4_Playground

A data visualization project using D3.js and Semantic UI
CSS
1
star