npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

serverless-inversify-util

v0.10.1

Published

A set of decorators to be used with inversify to generate serverless config and handlers.

Readme

Coverage Status Build Status

Serverless Inversify Util

This utility should be use in conjunction with the serverless framework.

Serverless Inversify Util is a simple utility that wraps serverless framework's config generation, mapping, and packing. This is accomplished using inversify, decorators, TypeScript compiler, and webpack. This project was heavily inspired by the inversify-express-utils / routing-controllers / spring boot and other similar frameworks / libraries.

This set of utilities is very opinionated in how they operate.

ChangeLog

To get an idea of changes between versions checkout the changelog

Installation

You can install serverless-inversify-util using npm:

$ npm install serverless-inversify-util inversify reflect-metadata

The type serverless-inversify-util definitions are included in the package as well.

Basics

Step 1: Create a Serverless Service

The Service decorator takes a config object that will be translated into the serverless.yml file. It also contains some additional metadata to know what handlers are associated with the service.


import {injectable} from "inversify";
import {Service} from "serverless-inversify-util";
import {TestHandler} from "./test-handler";

@Service({
    service: "test-service",
    provider: {
        name: "aws",
        stage: "test",
        region: "us-east-1"
    },
    handlers: [TestHandler]
})
@injectable()
export class TestService {

    public async preHandle(event: any, context: any): Promise<void> {
        // optional method that will be triggered before every handler method
    }
    
    public async postHandle(event: any, context: any, resp: any): Promise<any> {
        // optional method that will be triggered after every handler method
        // return the mutated response (or mutate the resp directly)
        return resp;
    }

}

Step 2: Create a Handler for the Service

A service can contain multiple handlers. However, at least one handler is required.


import {injectable} from "inversify";
import {HttpHandler, RequestContext, RequestEvent, RequestParam, RequestPath} from "serverless-inversify-util";

@injectable()
export class TestHandler {

    @HttpHandler("/testing/{id}", "GET")
    public testing(@RequestParam("val") val: string,
                   @RequestEvent() event: any,
                   @RequestContext() context: any,
                   @RequestPath("id") path: string): any {
        return {
            statusCode: 200,
            body: JSON.stringify({
                val,
                path,
                event,
                context
            })
        };
    }

}

Step 3: Setup the entry point for the serverless service

Now that the service and its handlers are created, the service needs to be added to the inversify container and the container needs to be registered with serverless-inversify-util.


import {Container} from "inversify";
import {IService, register, TYPE} from "serverless-inversify-util";
import {TestService} from "./test-service";

const container: Container = new Container();

container.bind<IService>(TYPE.Service).to(TestService).whenTargetNamed("TestService");

register(container);

Step 4: Generate deployment directory

Finally, the deployment directory needs to be generated. This directory will contain a generated serverless.yml, a generated handler.js, node_modules directory, and your project's compiled typescript code.

$ serverless-inversify-util -s ./path/to/entry_point.ts -p ./path/to/tsconfig.json -d -e test -t

Options

  • -s, --service (Required) The path to the entry point file
  • -p, --project (Required) The path to the tsconfig to use for compilation
  • -d, --deploy (Optional) Flag that denotes whether to run serverless deploy after generation
  • -e, --env (Optional) The stage / environment that will override the stage defined in the service
  • -t, --trim (Optional) Flag to ptionally trim lambda service name to be less than 64 characters

The service entry point (-s, --service) and the tsconfig path (-p, --project) are required. The paths can be absolute or relative.

There are two optional flags as well. -d, --deploy denotes whether the service should be deployed using serverless deploy after the generator is done, the default is to NOT deploy. -e, --env is the environment or stage to deploy to and if not specified will default to the stage specified in the @Service decorator.

serverless-inversify-util may need to be installed globally in order for the above command to run.

Docs

@RequestParam(name: string, parse?: ParseFunction)

RequestParam resolves a query parameter given the name of the parameter. The resolved value is not parsed in anyway.

    @HttpHandler("/testing", "GET")
    public testing(@RequestParam("val") one: string): any {
        return {
            statusCode: 200,
            body: JSON.stringify({
                one
            })
        };
    }

@RequestPath(path: string, method: string, [middleware: MiddlewareFunction, ...])

RequestPath resolves a path parameter given the name of the parameter. The resolved value is not parsed in anyway.

    @HttpHandler("/testing/{id}", "GET")
    public testing(@RequestPath("id") one: string): any {
        return {
            statusCode: 200,
            body: JSON.stringify({
                one
            })
        };
    }

@RequestEvent()

RequestEvent resolves the event that serverless receives.

    @HttpHandler("/testing", "GET")
    public testing(@RequestEvent() event: any): any {
        return {
            statusCode: 200,
            body: JSON.stringify({
                event
            })
        };
    }

@RequestEventValue(name: string, parse?: ParseFunction)

RequestEventVaue resolves a value that is on the event. For example, if event.path.on.event should be resolved, passing path.on.event would return the value from the event object.

    @HttpHandler("/testing", "GET")
    public testing(@RequestEventValue("path.on.event") event: any): any {
        return {
            statusCode: 200,
            body: JSON.stringify({
                event
            })
        };
    }

@RequestContext()

RequestContext resolves the context that serverless receives.

    @HttpHandler("/testing", "GET")
    public testing(@RequestContext() ctx: any): any {
        return {
            statusCode: 200,
            body: JSON.stringify({
                event
            })
        };
    }

@RequestContextValue(name: string, parse?: ParseFunction)

RequestContextValue resolves a value that is on the context. For example, if context.path.on.context should be resolved, passing path.on.context would return the value from the context object.

    @HttpHandler("/testing", "GET")
    public testing(@RequestContextValue("path.on.context") ctx: any): any {
        return {
            statusCode: 200,
            body: JSON.stringify({
                event
            })
        };
    }

@RequestBody(name: string, parse?: ParseFunction)

RequestBody resolves a value from the received body. This assumes content type of either application/json, application/x-www-form-urlencoded, or multipart/formdata.

    @HttpHandler("/testing", "GET")
    public testing(@RequestBody("val") one: any): any {
        return {
            statusCode: 200,
            body: JSON.stringify({
                one
            })
        };
    }

@RequestHeaderValue(header: string, parse?: ParseFunction)

RequestHeaderValue resolves a value from the request headers.

    @HttpHandler("/testing", "GET")
    public testing(@RequestHeaderValue("Content-Type") one: any): any {
        return {
            statusCode: 200,
            body: JSON.stringify({
                one
            })
        };
    }

@HttpHandler(path: string, method: string, ...middleware: MiddlewareFunction)

HttpHandler defines a handler that will listen for a http event. It requires the path and the method to watch for with the optional ability to have middleware. The middleware is called in the order that it is registered.

    @HttpHandler("/testing", "GET", (event, context) => {})
    public testing(): any {
        return {
            statusCode: 200
        };
    }

@S3Handler(bucket: string, event: string, ...middleware: MiddlewareFunction)

S3Handler defines a handler that will listen for an s3 event. It requires the bucket that the event should watch and the event that will be triggered on the bucket. Middleware can optionally be added which will run before the handler is called.

    @S3Handler("random.s3.bucket", "s3:ObjectCreated:*", (event, context) => {})
    public testing(): any {
        return {
            statusCode: 200
        };
    }

@ScheduleHandler(rate: string, options: IScheduleHandlerOptions, ...middleware: MiddlewareFunction)

ScheduleHandler defines a handler that will run a lambda on a schedule. It requires the rate at which to call the lambda and some options about the schedule. Middleware can optionally be added which will run before the handler is called.

    @ScheduleHandler("cron(0 12 * * ? *)", {enabled:true}, (event, context) => {})
    public testing(): void {
        // do something
    }

@IoTHandler(sql: string, name: string, ...middleware: MiddlewareFunction)

IoTHandler defines a handler that will listen for an IoT event. It requires the sql that the event should check and the name of the handler. Middleware can optionally be added which will run before the handler is called.

    @IoTHandler("select * from 'topic'", "eventHandlerName", (event, context) => {})
    public testing(): void {
        // do something
    }

@Handler(...events: IHandlerEvent[])

Handler is a generic type of handler that can receive the configuration needed for any type of event. The metadata passed to it will be used to generate the corresponding serverless.yml config. The below example is equivalent to the HttpHandler.

    @Handler({
        eventMap: {
            http: {
                path: "/testing",
                method: "GET"
            }
        },
        middleware: [(event: any, context: any) => void]
    })
    public testing(): any {
        return {
            statusCode: 200
        };
    }

@ErrorHandler(errorHandler: ErrorHandlerFunction)

ErrorHandler is a class level decorator aimed at being able to catch / intercept all errors thrown by a given handler class. If the error handler function returns an object it will be sent out as the resp, otherwise it will be sent out as an error. (e.g. callback(null, resp) if the handler returns something, callback(err) otherwise).


const errorHandler: ErrorHandlerFunction = (err: any): any => {

    // could also return undefined to propagate the err to the callback
    return {
        statusCode: 500,
        body: JSON.stringify({
            message: "My custom error message!",
            error: err
        })
    }
};

@injectable()
@ErrorHandler(errorHandler)
export class TestErrorHandler {

    @HttpMethod("/test", "GET")
    public testing(): any {
        throw new Error("This will trigger the error handler above!");
    }

}

@Service(data: IServiceData)

Service defines the root of the serverless service and all of the necessary metadata to generate and deploy the service.


@Service({
    service: "test-service",
    provider: {
        name: "aws",
        stage: "test",
        region: "us-east-1",
        environment: {
            "KEY": "value"
        },
        iamRoleStatements: [{
            Effect: "",
            Action: [""],
            Resource: ""
        }]
    },
    handlers: [TestHandler]
})
class TestService {

}

Generator

The generator is the core of serverless-inversify-util. It gathers all of the metadata, converts the metadata into a serverless.yml file, generates a handler.js file which maps all of the service handler's to the serverless.yml config, and finally packs all of the files using webpack which are ready to be deployed using serverless deploy.

The generator can be extended or be used in your own script to allow custom variations of script generation. This may be useful to add automatic deployment for each service or to even build multiple services.

The best way to understand how the generator works is to simply take a look at the execute method in generator.ts.

TODO

  1. Include more of the serverless config definition in the Service decorator.
  2. Allow multiple services to be registered.
    1. Accept multiple input entry files. We need to be able to compile and build each service separately.
  3. More default handlers (e.g. S3, etc)
  4. Add more documentation around Generator class
  5. Service level middleware (basically middleware that can be run first before every single event handler)
  6. Better webpack support (would be nice to somehow integrate ability to supply webpack.config.js or atleast a webpack config)