lambda-mdl
TypeScript icon, indicating that this package has built-in type declarations

1.2.7 • Public • Published

Type-safe middleware for AWS Lambda

Leveraging the power of Typescript to build middleware-like request handlers for lambda functions with type-based dependency checking.

TypeScript Test Coverage Status

Gif

An example

A service which parse request body as JSON, get a and b from it, check if both are valid numbers, then adds them and return result.

import { Err, MiddlewareCreator, Handler, JsonBodyService, ok, fail, creator, addService, jsonBodyService } from 'lambda-mdl';

type NumberService = { a: number; b: number };
type NumberErrNaN = Err<'NaA'>;
type NumberDependencies = JsonBodyService;

const numbers: MiddlewareCreator<{}, NumberService, NumberErrNaN, NumberDependencies> = () => {
  return async (request) => {
    const body = request.service.jsonBody;

    if (!(Number.isFinite(body.a) && Number.isFinite(body.b))) {
      return fail<NumberErrNaN>('NaA');
    }

    const service = body as NumberService;

    return addService(request, service);
  };
};

type Options = { acceptFloat: boolean };
type AdderService = { add: (a: number, b: number) => number };
type AdderErrNoFloats = Err<'Float'>;

const adder: MiddlewareCreator<Options, AdderService, AdderErrNoFloats> = (options, { throws }) => {
  return async (request) => {
    const service: AdderService = {
      add: (a: number, b: number) => {
        if (!options.acceptFloat && !(Number.isInteger(a) && Number.isInteger(b))) {
          throws<AdderErrNoFloats>('Float');
        }

        return a + b;
      },
    };

    return addService(request, service);
  };
};

const handler: Handler<AdderService & NumberService, number, never> = async ({
  service: { a, b, add },
}) => {
  return ok(add(a, b));
};

const lambda = creator(jsonBodyService).srv(numbers).srv(adder).ok(handler);

API

Defining services

Static service:

MiddlewareCreator

Type used for creating new services.

Params:

  • Options
  • Service
  • Errors
  • ServiceDeps
  • Event
import { Err, MiddlewareCreator, addService } from 'lambda-mdl';

type Options = { };
type Service = { add: (a: number, b: number) => number };
type Errors = never;

const service: MiddlewareCreator<Options, Service, Errors> = () => {
  return async (request) => {
    return addService(request, {
      add: (a: number, b: number) => {
        return a + b;
      },
    });
  };
};
Dynamic service:

Middleware

Used to define services dynamically based on provided options.

Params:

  • Service
  • Errors
  • ServiceDeps
  • Event
import { Middleware, ServiceContainer, Request, AwsEvent, empty, addService, creator } from 'lambda-mdl';

type Options = { test: number };
type Service<Opt> = Opt;
type Errors = never;

const service = <Opt extends Options>(
  options: Partial<Opt>
): Middleware<Opt, { data: Service<Opt> }, Errors> => {
  return async <Srv extends ServiceContainer>(request: Request<AwsEvent, Opt, Srv>) => {
    return addService(request, {
      data: { test: options.test } as Service<Opt>,
    });
  };
};

const res = creator(empty).opt({ test: 1 }).srv(service);

Initialization

creator

Starts the creation of the lambda chain.

Params:

  • creator: MiddlewareCreator
import { creator, empty } from 'lambda-mdl';

const res = creator(empty); // now you can use other methods, for example: .srv 

srv

Adds a new service.

Params:

  • creator: MiddlewareCreator
import { MiddlewareCreator, creator, empty, addService } from 'lambda-mdl';

const service: MiddlewareCreator<{}, {}, never> = () => {
  return async (request) => {
    return addService(request, {});
  }
};

const res = creator(empty).srv(service); 

opt

Set the options.

Params:

  • options

Handlers

ok

Adds a handler which will be run if all middleware creators executed successfully.

Params:

  • handler: Handler
import { ok, creator, empty } from 'lambda-mdl';

const res = creator(empty).ok(async () => {
  return ok('success'); // can be used in onOk
});

fail

Adds a handler which runs on middleware failure.

Params:

  • handler: HandlerError
import { ok, creator, empty } from 'lambda-mdl';

const res = creator(empty).fail(async () => {
  // this handler will not run because 
  // empty middleware won't fail
  
  return ok('success'); // can be used in onFail
});

fatal

Adds an unknown exception handler.

Params:

  • handler: HandlerException
import { ok, creator, empty } from 'lambda-mdl';

const res = creator(empty).fatal(async () => {
  // this handler will not run because 
  // empty middleware won't throw fatal errors
  
  return ok('success'); // can be used in onFatal
});

Transforms

onOk, onOkRes

Sets the result transformation of ok handler.

Params:

  • transform: Transform
import { ok, creator, empty } from 'lambda-mdl';

const res = creator(empty).ok(async () => {
  return ok('success');
}).onOk(async (result) => {
  return result; // result equals to 'success'
});

onFail, onFailRes

Sets the result transformation of fail handler.

Params:

  • transform: TransformError
import { ok, creator, empty } from 'lambda-mdl';

const res = creator(empty).fail(async () => {
  return ok('fail');
}).onFail(async (result) => {
  return result; // result equals to 'fail'
});

onFatal, onFatalRes

Sets the result transformation of fatal handler.

Params:

  • transform: TransformError
import { ok, creator, empty } from 'lambda-mdl';

const res = creator(empty).fatal(async () => {
  return ok('fatal');
}).onFatal(async (result) => {
  return result; // result equals to 'fatal'
});

on

Same as calling onOk, onFail and onFatal.

req

Returns AWS Lambda handler.


Packages

Packages allow grouping a service, and ok and fail handlers together.

import { Err, fail, ok } from 'lambda-res';
import { creator, empty, addService, ServiceOptions, Package } from 'lambda-mdl';

const pack: Package<
  ServiceOptions,
  { packageService: string },
  Err<'ServiceError'>,
  string,
  never,
  string
> = {
  srv: () => {
    return async (request) => {
      return addService(request, {
        packageService: 'service test',
      });
    };
  },
  ok: async () => {
    return ok(`ok`);
  },
  fail: async () => {
    return ok(`fail`);
  },
};

creator(empty)
  .pack(pack)
  .ok(async ({ service: { packageService } }) => {
    return ok(packageService);
  });

Dependents (0)

Package Sidebar

Install

npm i lambda-mdl

Weekly Downloads

32

Version

1.2.7

License

MIT

Unpacked Size

450 kB

Total Files

142

Last publish

Collaborators

  • alexshelkov