Skip to content

A collection of helpers to manage common tasks in aws lambda: ex. input validation/apigw responses/error management...

Notifications You must be signed in to change notification settings

andrea-lascola/aws-nodejs-kit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

56 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Release

Aws Nodejs Kit

This is a collection of generic typescript utilities to use in an aws lambda powered environment

Table of Contents

Installation

npm page: https://www.npmjs.com/package/aws-nodejs-kit

npm i aws-nodejs-kit 

Usage / Reference

Please refer to the /examples folder

NodeJS / Typescript utilities

Monads

import {Optional} from "aws-nodejs-kit";

const value: number | undefined = 10;

// Perform a list of computation without having to check explicitly for null/undefined value
const compute = Optional.fromValue(value)
    .map((val: number) => val + 10)
    .map((val: number) => val * 2)
    // Get the internal value, you can actually apply a default if the value is undefined
    .getOrElse(10);

console.log(compute); // 40

Logger

import {Logger} from "aws-nodejs-kit";

// Static Logger
const log = Logger.getInstance();

// Standard logs
log.debug("debug");
log.info("info");
log.warn("warn");
log.error("error");


// Log performance
log.time("log");
log.timeEnd("log");

Logging Decorators

import {CatchExceptionAndThrowIntegrationError} from "aws-nodejs-kit";
import {LogMetric, LogMetricSync} from "aws-nodejs-kit";

class Service {

    // Log Metric for async functions
    // This will result in the following log row:
    // METRIC 1021.351594000007 milliseconds getFeedByName feeds
    @LogMetric("getFeedByName", "feeds")
    public async getFeedByName() {

    }

    // Log Metric for sync functions
    // This will result in the following log row:
    // METRIC 1021.351594000007 milliseconds getFeedById feeds
    @LogMetricSync("getFeedById", "feeds")
    public getFeedById() {

    }

    // Catch errors for async functions
    // throw an IntegrationError, that, if used in conjuction with "catchErrors" Middleware generate a 429 http error
    // Used to propagate an integration error
    @CatchExceptionAndThrowIntegrationError()
    public async getFeedFromExternal() {

    }
}

Dates

import {dates} from "aws-nodejs-kit";

dates.datePlusTimeframe(new Date(), 1, dates.TimeUnit.hours);
// 2020-06-15T20:38:14.953Z

dates.dateFromISO(new Date().toISOString());
// 2020-06-15T19:38:14.956Z

dates.dateInHyphens(new Date());
// 2020-06-15

dates.dateInSeconds(new Date());
// 1592249894

dates.dateMinusTimeframe(new Date, 1, dates.TimeUnit.hours);
// 2020-06-15T18:38:14.960Z

dates.isDateGreaterThan(new Date(), 1, dates.TimeUnit.hours);
// true

dates.iSOFromTimestamp(new Date().getTime());
// 2020-06-15T19:41:11.301Z

dates.timestampFromISO(new Date().toISOString());
// 1592250071303

dates.timeframeToSeconds({amount: 1, timeUnit: dates.TimeUnit.hours});
// 3600

Exceptions

import {
    ValidationError,        // Maps to a 400 Status code
    UseCaseError,           // Maps to a 422 Status code
    IntegrationError,       // Maps to a 429 Status code
    NotFoundError,          // Maps to a 400 Status code
    UnAuthorizedError,      // Maps to a 401 Status code
    NotImplementedError,    // Used for abstract classes
} from "aws-nodejs-kit";

AWS Helpers

Lambda Core

import {catchErrors, Lambda} from "aws-nodejs-kit";
import {Logger} from "aws-nodejs-kit";
/**
 * Classic handler with business logic
 * @param event
 */
const handler = async (event: any) => {
    console.log(event);
};

// export a lambda Handler using handler
export const lambdaHandler = new Lambda(handler)
    // Add any middleware you need, this one catch errors and respond with standard api gateway responses
    .with(catchErrors(Logger.getInstance()))
    // Applying Middlewares
    .toFn();

Lambda Middlewares

// --- Default Middlewares includes:

// Log Lambda input event
.with(logEvent(Logger.getInstance()))

// Log Lambda response
.with(logResponse(Logger.getInstance()))

// Catch errors globally and return a apigw compatible response (map exceptions to status codes)
.with(catchErrors(Logger.getInstance()))

// Validate Lambda input event against a DTO (class decorated with "class-validator" decorators with static method "fromApiGWEvent")
// uses validate function to check- you should pass the "validator" function from "class-validator"  
.with(validateDTO(Logger.getInstance(),
    (event) => MyDTO.fromApiGWEvent(event),
    validate))

// You can create your custom Middleware implementing the "Middleware" type and passing your object to the .with() function

DynamoDb

// TODO complete doc

Api Gateway

import {ResponseBuilder} from "aws-nodejs-kit";

let handler;

/**
 * Return Api Gateway compatible responses
 * @param event
 */
handler = async (event: any) => {
    /**
     * http status code -> 200
     * response(enveloped) -> {
     *     data : {}
     * }
     */
    return new ResponseBuilder().build().resOk({data: {}});
    /**
     * http status code -> 204
     * response(enveloped) -> {
     *     data : {}
     * }
     * used mainly for POST/DELETE/PUT APIs
     */
    return new ResponseBuilder().build().resOkNoContent({data: {}});
};


/**
 * Return Bad Request responses:
 *
 * response(enveloped) -> {
 *      error: {
 *          errorMessage: errorMessage || "The request could not be understood by the server due to malformed syntax. The client should not repeat the request without modifications",
 *          errorCode: errorCode || "",
 *          payload
 *      }
 * }
 * @param event
 */
handler = async (event: any) => {
    /**
     * http status code -> 400
     */
    return new ResponseBuilder().build().resBadReq(
        {}, // optional payload,
        "xxx", // optional errorCode,
        "Invalid" // optional errorMessage,
    );
    /**
     * http status code -> 404
     * used for missing content
     */
    return new ResponseBuilder().build().resNotFound();
    /**
     * http status code -> 429
     * an error while communicating with a third party service happened
     */
    return new ResponseBuilder().build().resIntegrationError();
    /**
     * http status code -> 422
     * used for a business logic un-manageable error (better than a 500 aint'it?)
     */
    return new ResponseBuilder().build().resUseCaseError();
    /**
     * http status code -> 403
     * you are not allowed to see this content
     */
    return new ResponseBuilder().build().resForbidden();
};

Contributing

npm install
npm run build
npm run test
npm run test:coverage // tests with coverage report
  • PRs are welcome
  • The release process uses github actions and semantic-release for automatic tagging/versioning/publishing to npm
  • The commit messages MUST follow the conventional commit convention

About

A collection of helpers to manage common tasks in aws lambda: ex. input validation/apigw responses/error management...

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •