UNPKG

8.97 kBMarkdownView Raw
1<p align="center">
2 <a href="https://github.com/juliantellez/lambcycle" target="_blank">
3 <img alt="lambcycle" src="https://raw.githubusercontent.com/juliantellez/lambcycle/master/assets/lambcycle-logo.svg?sanitize=true" width="144">
4 </a>
5</p>
6
7<p align="center">
8 Lambcycle is a declarative <a href="https://aws.amazon.com/lambda/" target="_blank">lambda</a> middleware. Its main purpose is to let you focus on the specifics of your application by providing a configuration cycle.
9</p>
10
11<!---links--->
12
13<p align="center">
14<!---npm--->
15<a href="https://www.npmjs.com/package/lambcycle" target="_blank">
16 <img src="https://img.shields.io/npm/v/lambcycle.svg?style=flat-square" style="padding:3px">
17</a>
18
19<!---npm downloads--->
20<a href="https://npmcharts.com/compare/lambcycle?minimal=true" target="_blank">
21 <img src="https://img.shields.io/npm/dm/lambcycle.svg?style=flat-square" style="padding:3px">
22</a>
23
24<!---travis master build--->
25<a href="https://travis-ci.org/juliantellez/lambcycle/" target="_blank">
26 <img src="https://img.shields.io/travis/juliantellez/lambcycle/master.svg?style=flat-square" style="padding:3px">
27</a>
28
29<!---install size--->
30<a href="https://packagephobia.now.sh/result?p=lambcycle" target="_blank">
31 <img src="https://packagephobia.now.sh/badge?p=lambcycle"style="padding:3px">
32</a>
33
34<!---npm dependencies--->
35<a href="https://david-dm.org/juliantellez/lambcycle" target="_blank">
36 <img src="https://david-dm.org/juliantellez/lambcycle/status.svg" style="padding:3px">
37</a>
38
39<!---npm dev-dependencies--->
40<a href="https://david-dm.org/juliantellez/lambcycle?type=dev" target="_blank">
41 <img src="https://david-dm.org/juliantellez/lambcycle/dev-status.svg" style="padding:3px">
42</a>
43
44<!---coveralls--->
45<a href="https://coveralls.io/github/juliantellez/lambcycle" target="_blank">
46 <img src="https://coveralls.io/repos/github/juliantellez/lambcycle/badge.svg?branch=master" style="padding:3px">
47</a>
48
49<!---npm dependency updates--->
50<a href="https://snyk.io/test/github/juliantellez/lambcycle?targetFile=package.json" target="_blank">
51 <img src="https://snyk.io/test/github/juliantellez/lambcycle/badge.svg?targetFile=package.json" alt="Known Vulnerabilities" style="max-width:100%; padding:3px;">
52</a>
53
54<!---serverless--->
55<a href="http://www.serverless.com" target="_blank">
56 <img src="http://public.serverless.com/badges/v3.svg" alt="Serverless" style="max-width:100%; padding:3px;">
57</a>
58
59<!---MIT License--->
60<a href="https://opensource.org/licenses/MIT" target="_blank">
61 <img src="http://img.shields.io/badge/license-MIT-blue.svg?style=flat" alt="MIT License" style="max-width:100%; padding:3px;">
62</a>
63
64<!---FOSSA--->
65<a href="https://app.fossa.io/projects/git%2Bgithub.com%2Fjuliantellez%2Flambcycle?ref=badge_shield" target="_blank">
66 <img src="https://app.fossa.io/api/projects/git%2Bgithub.com%2Fjuliantellez%2Flambcycle.svg?type=shield" alt="FOSSA Status" style="max-width:100%; padding:3px;">
67</a>
68</p>
69
70 - [Install](#install)
71 - [Introduction](#Introduction)
72 - [Handler Lifecycle](#Handler-lifecycle)
73 - [Error Handling](#Error-handling)
74 - [Plugins](#plugins)
75 - [Creating a Plugin](#creating-a-plugin)
76 - [Using a Plugin](#using-a-plugin)
77 - [About the project](#about-the-project)
78 - [Contributing](#contributing)
79 - [License](#license)
80
81# Install
82
83```bash
84# with npm
85npm install --save lambcycle
86
87# with yarn
88yarn add lambcycle
89```
90
91# Introduction
92
93Lambcycle is a middleware for lambda functions. It defines a configurable life-cycle and allows you to focus on your application's logic. It has a "Feature as Plugin" approach, so you can easily create your own plugins or reuse your favorite packages with very little effort 🐑 🛵.
94
95Checkout the following example or follow the link to
96[🎉 see some actual code 🎉 ](https://github.com/juliantellez/lambcycle/tree/master/examples).
97
98
99```javascript
100// with es6
101
102import Joi from "joi";
103import lambcycle from "lambcycle";
104
105import pinoPlugin from './myPinoPlugin'
106import joiPlugin from './myJoiPlugin'
107import bodyParserPlugin from './myBodyParserPlugin'
108
109import applicationLogic from "./mycode";
110
111const processData = async (event, context) => {
112 // beautiful application logic ...
113
114 const manipulateData = event => {
115 // ...
116 };
117
118 return await applicationLogic(manipulateData(event), context);
119};
120
121const schema = Joi.object()
122 .keys({
123 username: Joi.string().alphanum().min(5).required(),
124 password: Joi.string().regex(/^[a-zA-Z0-9]{5,30}$/),
125 email: Joi.string().email({ minDomainAtoms: 2 })
126 });
127
128const handler = lambcycle(processData).register([
129 pinoPlugin,
130 bodyParserPlugin,
131 joiPlugin(schema)
132]);
133
134export default handler;
135```
136
137# Handler lifecycle
138
139The lifecycle provides a clear guideline to reason about your needs. Every step of the cycle can handle or throw errors making it easy to log, report or debug.
140
141<p align="center">
142<img src="https://raw.githubusercontent.com/juliantellez/lambcycle/master/assets/lifecycle.svg?sanitize=true" height=500>
143</p>
144
145# Error Handling
146As you can see from the lifecycle graph above, the error object is a first class citizen that will stop the cycle and execute any error plugins declared in the register, it will then proceed to call the lambda handler's callback.
147Have a look at the [Wrapper Interface](https://github.com/juliantellez/lambcycle/blob/master/src/Interfaces/IWrapper.ts) to see what's available for reporting.
148
149`HINT: pretty much everything.`
150
151```javascript
152import lambcycle from 'lambcycle'
153import notifyError from './myErrorNofifier'
154
155const appLogic = async(event, context) => {
156 const {error, data} = await amazingJob()
157 if(error) {
158 throw error
159 }
160}
161
162const errorNotifier = {
163 plugin: {
164 onError: async (handler) => {
165 /**
166 * See IWrapper interface
167 */
168 await notifyError(handler.error)
169 }
170 }
171}
172
173const handler = lambcycle(appLogic).register([errorNotifier])
174
175export default handler;
176```
177
178
179# Plugins
180
181- [BodyParser](https://github.com/juliantellez/lambcycle/tree/master/src/Plugins/BodyParser): Parse incoming request bodies before your handler, available under the `handler.event.body` property.
182- [Joi](https://github.com/juliantellez/lambcycle/tree/master/src/Plugins/Joi): Object schema description language and validator for JavaScript objects. Validate requests without the pain!
183
184# Creating a plugin
185
186A plugin is an object that can attach its hooks to one or more event cycles, it may provide its own configuration object.
187
188```typescript
189type IPluginHookFunction = (
190 wrapper: IWrapper,
191 config: object,
192 handleError?: Callback
193) => void;
194```
195
196```typescript
197import * as Sentry from '@sentry/node';
198import MyAwesomeIntegration from './MyAwesomeIntegration'
199
200const sentryPlugin = (config) => {
201 Sentry.init({
202 dsn: `https://config.key@sentry.io/${config.project}`,
203 integrations: [new MyAwesomeIntegration()]
204 });
205
206 return {
207 config,
208 plugin: {
209 onPreResponse: async (handlerWrapper, config) => {
210 Sentry.captureMessage('some percentile log perhaps?')
211 },
212 onError: async (handlerWrapper, config) => {
213 Sentry.captureException(handlerWrapper.error);
214 }
215 }
216 }
217}
218
219export default sentryPlugin;
220```
221
222# Using a plugin
223
224Let's reuse the example above. Make sure your lambdas follow the [Principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege) and your secrets stay SECRET ㊙️
225
226```typescript
227import lambcycle from 'lambcycle'
228import sentryPlugin from './sentryPlugin'
229
230const myApplicationLogic = async (event, context) => {
231 await someLogic()
232}
233
234const handler = lambcycle(myApplicationLogic)
235.register([
236 sentryPlugin({
237 key: process.env.SENTRY_KEY,
238 project: process.env.SENTRY_PROJECT,
239 })
240]);
241
242export default handler;
243```
244
245# About the project
246
247This project has been built with lots of ❤️ and [Typescript](https://www.typescriptlang.org) 🤣. It embraces the middleware pattern and uses types for consistency and documentation. If this approach seems familiar to you is because it was inspired by the awesome [hapijs](https://hapijs.com/api#request-lifecycle).
248
249# Contributing
250As you can see the possibilities are endless when it comes to plugins! Everyone is welcome to [contribute](https://github.com/juliantellez/lambcycle/blob/develop/contributing.md)! Feel free to create [issues](https://github.com/juliantellez/labmcycle/issues) or [prs](https://github.com/juliantellez/labmcycle/pulls).
251
252
253# License
254[MIT License](https://github.com/juliantellez/lambcycle/blob/master/LICENSE)
255
256
257<a href="https://app.fossa.io/projects/git%2Bgithub.com%2Fjuliantellez%2Flambcycle?ref=badge_large" target="_blank">
258 <img src="https://app.fossa.io/api/projects/git%2Bgithub.com%2Fjuliantellez%2Flambcycle.svg?type=large" alt="FOSSA Status" style="max-width:100%; padding:3px;">
259</a>