GithubHelp home page GithubHelp logo

niledaley / lambda-hooks Goto Github PK

View Code? Open in Web Editor NEW

This project forked from sweeetland/lambda-hooks

0.0 1.0 0.0 70 KB

Super simple lightweight hooks to avoid repeated logic in your Node.js lambda functions

License: MIT License

JavaScript 15.41% TypeScript 84.59%

lambda-hooks's Introduction

lambda-hooks ⚓️

Super lightweight module to hook into the execution of your Node.js lambda functions

Lambda Hooks help avoid repeated logic in your lambda functions. Use some of the provided hooks or easily create your own. They are just functions that can be executed before, after or when an error occurs.

Principles

  • Zero dependancies
  • Fast & simple to use
  • First class support for TypeScript & modern JavaScript

Example

const useHooks, {logEvent, parseEvent, handleUnexpectedError} = require('lambda-hooks')

// call useHooks with hooks to decorate your lambda with
const withHooks = useHooks({
	before: [logEvent(), parseEvent()],
	after: [],
	onError: [handleUnexpectedError()]
})

const handler = async (event, context) => {
	// your lambda function...
}

// call withHooks passing in your lambda function
exports.handler = withHooks(handler)

Install

Using npm:

npm install lambda-hooks

or with yarn:

yarn add lambda-hooks

TypeScript types are included 🧰

Usage

  1. Import/require the package
const useHooks = require('lambda-hooks')
  1. Call useHooks with the hooks that you want to use. There's 3 types of hooks that are executed either before the lambda execution, after or if an error occurs.

    Note that the order of the hooks matters, they are executed one by one from the first hook in the before array.

    Also, notice that we are invoking the hooks when they are passed in, this is deliberate and will make more sense when we get to a more complex example later.

const withHooks = useHooks({
    before: [logEvent(), parseEvent()],
    after: [],
    onError: [handleUnexpectedError()],
})
  1. useHooks returns a function withHooks. Pass your async lambda into the withHooks function to decorate your lambda and then export as normal.
const  handler = async (event, context) => {...}

exports.handler = withHooks(handler)

What the hook? 👀

I'm glad you asked, let's start with a simple example of a hook that logs the event

export const logEvent = () => async state => {
    console.log(`received event: ${state.event}`)

    return state
}

Notice that we have a function that returns a function, a higher order function. The parent function is the HookCreator and the returned function is the HookHandler. We'll get to why later.

For now, let's focus on the returned function the HookHandler. This function receives and returns a state object that looks like this:

interface State {
    event: Event // AWS lambda event
    context: Context // AWS lambda context
    exit: boolean // Set to true to quit execution early
    response?: Response // This will contain the response from your lambda after it has been executed. Also this will be returned when exit is true
    error?: Error // If there's an unhandled exception, it will be attached here & your onError handlers will be invoked
}

You can write hooks to manipulate the event before it reaches your lambda function. For example, when writing lambdas that sit behind an API often you need to parse the event body. Let's do exactly that:

export const parseEventBody = () => async state => {
    const { event } = state

    if (typeof event.body === 'string') {
        state.event.body = JSON.parse(event.body)
    }

    return state
}

Ok you get the gist, now it's time for a more complex example. Again, when creating lambdas that sit behind a rest API, it's a good idea to validate the event body (assuming this hasn't already been done by API gateway). Like so:

export const validateEventBody = ({ schema }) => async state => {
    if (!schema) {
        throw Error('missing required schema for validation')
    }

    try {
        const { event } = state

        await schema.validate(event.body, { strict: true })

        console.log(`yup body passed validation: ${event.body}`)
    } catch (error) {
        console.log(`yup error validating body: ${error}`)

        state.exit = true
        state.response = { statusCode: 400, body: JSON.stringify({ error: error.message }) }
    }

    return state
}

Here we are utilising a library called yup for validation. Usually validation libraries need a schema to validate against, but how do we have access to the schema from inside the hook at the point of execution?

That's why we have a higher order function, the HookCreator. This is to pass in anything that the hooks need that isn't already on the state object. See in this example we pass in the request schema to the HookCreator. This means that at the point of execution, we now have access to the schema in the HookHandler.

But for this to work though, we need to remember to pass in the schema to the HookCreator when we invoke useHooks. Like so:

const withHooks = useHooks({
    before: [logEvent(), parseEvent(), validateEventBody({ schema })],
})

As you can see, when creating hooks like this, the possibilities are endless. You just have to use your imagination... 🧠

Woah calm down, actually there are a few rules ☝️

Rules of Hooks

  1. A hook must be a higher order function
  2. The returned function (HookHandler) must be async or return a promise
  3. The HookHandler accepts the state object as input and must return the state object
  4. Your lambda function must be async

lambda-hooks's People

Contributors

niledaley avatar sweeetland 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.