Giter Club home page Giter Club logo

aws-lambda-framework's Introduction

AWS Lambda Framework

npm build coverage dependencies vulnerabilities license PRs Welcome Join the chat at https://gitter.im/aws-lambda-framework/community

A framework for simplifying writing AWS Lambda functions in typescript featuring IoC with services for input validation, sending slack notifications, connecting to databases, and using AWS services.

For release notes, see the CHANGELOG

This project is still in the early stages, any feedback is much appreciated. Please let me know of any services or features you feel could improve this framework!

Motivation

When developing microservice architectures on aws, a lot of common functionality has to be implemented into each Lambda function. This framework has been developed to provide that scaffolding as well streamline error handling and responses, such that anyone using Lambda functions through an API can always expect the same output.

Installation

npm i aws-lambda-framework --save

Usage

To utilize the framework your Lambda functions should extend the BaseLambda abstract class. This class provides scaffolding for your Lambda functions, ensuring that any results or errors are properly formatted for APIGateway and sent back to the caller. Errors are automatically logged and optionally send to a Slack channel of your choice. New Lambda functions must implement an invoke function, which ensures that the previously mentions points occur. This function also returns a LambdaResult to standardize the results for the end user, containing a userMessage and optionally a data object.

Basic example

// class TestLambda.ts

import {
  BaseLambda,
  LambdaContainer,
  APIGatewayProxyEvent,
  Context,
  APIGatewayProxyResult,
  LambdaResult,
  Mysql,
  LambdaError
} from '../../src/aws-lambda-framework'

class TestLambda extends BaseLambda {
  constructor(event: APIGatewayProxyEvent, context: Context) {
    super(event, context)
  }

  async invoke(): Promise<LambdaResult> {
    try {
      const res = await LambdaContainer.get(Mysql).execute<Country>({
        sql: process.env.MYSQL_TEST_SQL!
      })

      return {
        userMessage: 'Successfully tested Lambda!',
        data: res.rows
      }
    } catch (err) {
      throw new LambdaError(err.message, err.stack, 'Failed to Test Lambda!')
    }
  }
}

export function handler(event: APIGatewayProxyEvent, context: Context): Promise<APIGatewayProxyResult> {
  return new TestLambda(event, context).handler()
}

// interface Country.ts
interface Country {
  id: number
  name: string
  locale: string
  countryCode: number
}

Kitchensink Example

// KitchensinkLambda.ts

import {
  BaseLambda,
  APIGatewayProxyEvent,
  Context,
  LambdaResult,
  LambdaContainer,
  Property
} from '../../src/aws-lambda-framework'
import { inject } from 'inversify'
import { KitchensinkRepository } from './KitchensinkRepository'
import { UpdateKitchensinkRequest } from './UpdateKitchensinkRequest'
import { validatePermissions } from './validatePermissions'
import { validateRequest } from './validateRequest'

class KitchensinkLambda extends BaseLambda {
  @inject(KitchensinkRepository) private repo: KitchensinkRepository
  request: UpdateKitchensinkRequest

  constructor(event: APIGatewayProxyEvent, context: Context) {
    super(event, context)
    this.request = LambdaContainer.get<UpdateKitchensinkRequest>(Property.EVENT_BODY)
  }

  async invoke(): Promise<LambdaResult> {
    validatePermissions(['Superusers'])
    await validateRequest(this.request)

    const res = await this.repo.updateKitchenSink(this.request.updatedKitchensink)

    return {
      userMessage: 'Successfully updated Kitchensink!',
      data: res.metadata
    }
  }
}

export function handler(event: APIGatewayProxyEvent, context: Context) {
  return new KitchensinkLambda(event, context)
}

// Kitchensink.ts

import { IsInt, Min, Max } from 'class-validator'

export class Kitchensink {
  id: number
  @IsInt()
  @Min(40)
  @Max(200)
  height: number
  @IsInt()
  @Min(80)
  @Max(400)
  width: number
}

// KitchensinkRepository.ts

import { injectable, inject } from 'inversify'
import { Mysql, Query } from '../../src/aws-lambda-framework'
import { QueryResult } from '../../src/framework/interfaces/QueryResult'
import { Kitchensink } from './Kitchensink'

@injectable()
export class KitchensinkRepository {
  @inject(Mysql) private mysql: Mysql

  async updateKitchenSink(kitchensink: Kitchensink): Promise<QueryResult<void>> {
    const query: Query = {
      sql: `
        UPDATE
          some_table (id, height, width)
        VALUES (
          ?,?,?
        )`,
      inputs: [kitchensink.id, kitchensink.height, kitchensink.width]
    }

    return this.mysql.execute(query)
  }
}

// UpdateKitchensinkRequest.ts

import { Kitchensink } from './Kitchensink'

export class UpdateKitchensinkRequest {
  updatedKitchensink: Kitchensink
}

// validatePermissions.ts

import { Property, LambdaContainer, CognitoToken, UnauthorizedError } from '../../src/aws-lambda-framework'

export function validatePermissions(whitelistedCognitoGroups: string[]): void {
  const cognitoGroups = LambdaContainer.get<CognitoToken>(Property.COGNITO_TOKEN)['cognito:groups']
  if (cognitoGroups.some(g => whitelistedCognitoGroups.includes(g))) throw new UnauthorizedError()
}

// validateRequest.ts

import { Validator, LambdaContainer, ValidationError } from '../../src/aws-lambda-framework'

export function validateRequest(request: object): Promise<void> {
  return LambdaContainer.get(Validator)
    .validateOrReject(request)
    .catch(errors => {
      throw new ValidationError(errors)
    })
}

Services

The framework provides easy access to some of the tools that are often needed when writing Lambda functions. These are injected as singletons into the Container the first time they are called.

Validator

Mysql

Postgres

SlackNotifier

AWS Services

  • APIGateway
  • Aurora
  • Cloudwatch
  • DynamoDB
  • DynamoDC (Document Client)
  • Kinesis
  • Lambda
  • RDS
  • Redshift
  • S3
  • SES
  • SSM

aws-lambda-framework's People

Contributors

dhjartvar avatar gitter-badger avatar mindnuts avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.