Skip to content

Commit e44d3cf

Browse files
committed
updated docs
1 parent 147cb75 commit e44d3cf

File tree

2 files changed

+127
-40
lines changed

2 files changed

+127
-40
lines changed

README.md

+120-39
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
# convert-lambda-to-express
22

3-
Production-ready package to run your lambda workloads as an express server. Build with the developer (me :P) in mind and makes development of lambda api's a breeze. This package was developed because the other options available for running lambdas, like [sam local start-api](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-local-start-api.html) [serverless-offline](https://github.com/dherault/serverless-offline) or [docker-lambda](https://github.com/lambci/docker-lambda), require docker containers and are VERY slow hot-reloading or do not provide that feature at all (how does one dev without hot reload these days?!?!).
3+
Production-ready package to run your lambda workloads as an express server. Built with both developers and enterprise in mind.
4+
5+
`convert-lambda-to-express` provides fully features `event` and `context` objects to your handlers and there should be no need to modify your existing code. If you rely on the `ENVIRONMENT` variables that lambda provides, those are accounted for as well.
46

57
Running apiGateway/lambda locally during development can be a challenge (to say the least). The other options out there are either too slow or too complicated. This package aims to solve this problem by providing a simple way to run your api locally. It allows you to wrap your handlers and serve them from an express server.
68

7-
`convert-lambda-to-express` provides fully features `event` and `context` objects to your handlers and there should be no need to modify your existing code. If you rely on the ENVIRONMENT variables that lambda provides, those are accounted for as well.
9+
Makes development of lambda api's a breeze. This package was developed because the other options available for running lambdas, like [sam local](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-local-start-api.html), [serverless-offline](https://github.com/dherault/serverless-offline) or [docker-lambda](https://github.com/lambci/docker-lambda), require docker containers. They are all VERY slow hot-reloading or do not provide that feature at all (how does one dev without hot reload these days?!?!).
10+
11+
There are even some great use cases for migrating workloads away from Lambda and this is the project for you.
812

9-
There are even some great use cases for migrating workloads away from Lambda and this is the project for you. Hate your, now baked-in, vendor lock with the non-portable lambda function signature? Have you found that concurrency limits with very choppy traffic for extremely high workloads make it hard to reserve concurrency for and just want to use an auto-scaling group or kubernetes cluster now that you've grown? Do you have long running, but very low resource tasks that end up costing an arm and leg on Lambda. Depending on your specifics it can end up being much more effective/cost-efficient to run you system on EC2 or on a kubernetes cluster. Rest assured this is a production-ready package that is built for a bulletproof base with express.
13+
Hate your, now baked-in, vendor lock and the non-portable lambda function signature? Have you found that concurrency limits for very choppy traffic and extremely high workloads hard to reserve concurrency for? Just want to use an auto-scaling group or kubernetes cluster now that you've grown? Do you have long running, but very low resource tasks that end up costing an arm and leg on Lambda. Depending on your specifics it can end up being much more effective/cost-efficient to run you system on EC2 or a kubernetes cluster. Rest assured this is a production-ready package that is built for a bulletproof base with express.
1014

11-
If you love this package and want to [thank me](https://www.paypal.com/donate?hosted_button_id=HCF76TA62TXJW), or contract with me, you can find me at [Matthew Keil](https://www.linkedin.com/in/matthew-keil/). I specialize in DevOps, Security(SecOps) and Crypto/Solidity development. Open-source for the win!
15+
If you love this package and want to [thank me](https://www.paypal.com/donate?hosted_button_id=HCF76TA62TXJW), or contract with me, you can find me at [Matthew Keil](https://www.linkedin.com/in/matthew-keil/). I specialize in Crypto/Solidity, DevOps and Security(SecOps) development. Open-source for the win!
1216

1317
## Install
1418

@@ -19,89 +23,166 @@ npm install -S convert-lambda-to-express
1923
## Basic usage
2024

2125
```typescript
22-
import { wrapLambda } from "convert-lambda-to-express";
23-
import express from "express";
24-
import { handler } from "./someLambdaHandler";
26+
import { wrapLambda } from 'convert-lambda-to-express';
27+
import express from 'express';
28+
import { handler } from './someLambdaHandler';
2529

2630
const app = express();
2731

28-
app.get("/", wrapLambda(handler));
32+
app.get('/', wrapLambda(handler));
2933

3034
app.listen(3000, () => {
31-
console.log("Listening on port 3000");
35+
console.log('Listening on port 3000');
3236
});
3337
```
3438

3539
## Advanced usage
3640

3741
```typescript
38-
import express from "express";
39-
import { wrapLambda, WrapperOptions } from "convert-lambda-to-express";
40-
import { handler } from "./someLambdaHandler";
42+
import express from 'express';
43+
import { wrapLambda, WrapperOptions } from 'convert-lambda-to-express';
44+
import { handler } from './someLambdaHandler';
4145

4246
const app = express();
4347

4448
const options: WrapperOptions = {
45-
functionName: "my-function",
46-
resourcePath: "/api/v1/my-function",
47-
profile: "my-aws-credentials-profile", // from ~/.aws/credentials
48-
region: "us-east-1", // sets AWS_REGION for sdk calls in handler
49+
functionName: 'my-function',
50+
resourcePath: '/api/v1/my-function',
51+
profile: 'my-aws-credentials-profile', // from ~/.aws/credentials
52+
region: 'us-east-1', // sets AWS_REGION for sdk calls in handler
4953
timeoutInSeconds: 10, // sets actual timeout for handler
5054
finalize: () => {
5155
// do some cleanup here after function runs but before
5256
// response is sent to client
53-
},
57+
}
5458
};
5559

5660
app.get(config.resourcePath, wrapLambda(handler, options));
5761

5862
app.listen(3000, () => {
59-
console.log("Listening on port 3000");
63+
console.log('Listening on port 3000');
6064
});
6165
```
6266

67+
## Hot-Reloading DevServer (useful with cdk)
68+
69+
You can import the `addToDevServer` into your cdk constructs and add the handlers during run time. This was the designed use case. See [`matthewkeil/full-stack-pattern`](https://github.com/matthewkeil/full-stack-pattern) for an example. Also works well with sam templates or any other method for programmatically building the handlers array in the example below. In the cdk instance, instead of calling app.synth() call startDevServer() and it will give you a hot reloading api.
70+
71+
```typescript
72+
import { addToDevServer, startDevServer, HandlerConfig } from 'convert-lambda-to-express';
73+
import { middlewareHandler } from './someCorporateMiddleware';
74+
75+
// HandlerConfig extends WrapperOptions
76+
const handlers: HandlerConfig[] = [
77+
{
78+
profile: 'my-aws-credentials-profile', // from ~/.aws/credentials
79+
region: 'us-east-1', // sets AWS_REGION for sdk calls in handler
80+
method: 'GET',
81+
path: '/path/{param1}/{param2}',
82+
handler: 'doSomethingFancy/index.handler',
83+
codeDirectory: './path/to/code/directory', // where `doSomething` fancy folder is located
84+
environment: {
85+
ENV_VAR: 'value'
86+
}
87+
}
88+
];
89+
90+
for (const handler of handlers) {
91+
addToDevServer(handler);
92+
}
93+
94+
const port = 3002;
95+
96+
startDevServer({
97+
port,
98+
prod: true,
99+
hotReload: true, // will watch all `handler.codeDirectory` paths for changes and restart server
100+
corsOptions: {
101+
// cors package options
102+
origin: `http://localhost:${port}`,
103+
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
104+
preflightContinue: false,
105+
optionsSuccessStatus: 204
106+
},
107+
helmetOptions: {
108+
// helmet package options, pick better options than this example please...
109+
noSniff: true,
110+
xssFilter: true
111+
}
112+
});
113+
```
63114

64-
## WrapperOptions
115+
## WrapperOptions, HandlerConfig and DevServerConfig
65116

66-
Configure your lambdas with the the `options` object:
117+
Configure your lambdas and devServer with these `options` objects:
67118

68119
```typescript
69120
export interface WrapperOptions {
121+
handler?: string;
70122
functionName?: string;
71-
resourcePath?: string;
72-
profile?: string;
73-
region?: string;
74-
accountId?: string;
123+
functionVersion?: string;
124+
memorySize?: number;
125+
logGroupName?: string;
126+
logStreamName?: string;
75127
timeoutInSeconds?: number;
76-
stage?: string;
77-
isBase64Encoded?: boolean;
78-
handler?: string;
79-
nodeModulesPath?: string;
80128
identity?: CognitoIdentity;
81129
clientContext?: ClientContext;
130+
nodeModulesPath?: string;
131+
resourcePath?: string;
132+
stage?: string;
133+
isBase64Encoded?: boolean;
82134
finalize?: () => void;
83-
logger?: Logger;
84-
defaultHeaders?: { [header: string]: string | number | boolean };
135+
accountId?: string;
136+
region?: string;
137+
profile?: string;
138+
credentialsFilename?: string;
139+
logger?: Logger; // winston logger
140+
defaultResponseHeaders?: { [header: string]: string | number | boolean };
141+
}
142+
143+
export interface HandlerConfig extends WrapperOptions {
144+
method: HttpMethod;
145+
resourcePath: string;
146+
handler: string;
147+
codeDirectory?: string;
148+
environment?: HandlerEnvironment;
149+
}
150+
151+
export interface DevServerConfig {
152+
port?: number;
153+
hotReload?: boolean;
154+
prod?: boolean;
155+
morganSetting?: MorganOption;
156+
corsOptions?: CorsOptions;
157+
helmetOptions?: Parameters<typeof helmet>[0];
158+
middleware?: Handler[];
159+
verbose?: boolean;
160+
codeDirectory?: string;
85161
}
86162
```
87163

88164
| Key name | Description |
89165
| --- | --- |
166+
| `method` | HTTP method to use for the handler|
167+
| `resourcePath`|defaults to `/{proxy+}` Placed in ENVIRONMENT, `event` and `context`|
168+
| `handler`|`filename.exportName` format. Placed in ENVIRONMENT|
169+
| `codeDirectory`|used to import handler and for watching code changes|
170+
| `environment`|environment variables|
90171
| `functionName`|optional, defaults to `convert-lambda-to-express`. Placed in ENVIRONMENT, `event` and `context`|
91-
| `resourcePath`|optional, defaults to `/${proxy+}` Placed in ENVIRONMENT, `event` and `context`|
92-
| `profile`|optional, defaults to `default`. profile from `~/.aws/credential` to use. Adds tokens to AWS_TOKEN, AWS_SECRET_TOKEN, AWS_SESSION_TOKEN|
93-
| `region`|optional, AWS region, default to `us-east-1`. adds AWS_REGION to ENVIRONMENT|
94-
| `accountId`|optional, aws account id. Placed in ENVIRONMENT|
172+
| `functionVersion`|optional, defaults to `$LATEST`. Placed in ENVIRONMENT|
95173
| `timeoutInSeconds`|optional, default to `3`. watchdog timer that mimics lambda's timeout|
96-
| `stage`|optional, defaults to `dev`. Passed in `event`|
97-
| `isBase64Encoded`|optional, default to `false`. Passed in to handler `event`|
98-
| `handler`|optional, in `filename.exportName` format. Placed in ENVIRONMENT|
99-
| `nodeModulesPath`|optional, path to local node_modules folder. Placed in ENVIRONMENT|
100174
| `identity`|optional, CognitoIdentity object, see [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/7b62f878cc218c8e94e6efafa55cea6796b501f7/types/aws-lambda/handler.d.ts#L124). Passed in `context`|
101175
| `clientContext`|optional, ClientContext object, see [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/7b62f878cc218c8e94e6efafa55cea6796b501f7/types/aws-lambda/handler.d.ts#L129). Passed in `context`|
176+
| `nodeModulesPath`|optional, path to local node_modules folder. Placed in ENVIRONMENT|
177+
| `stage`|optional, defaults to `dev`. Passed in `event`|
178+
| `isBase64Encoded`|optional, default to `false`. Passed in to handler `event`|
102179
| `finalize`|optional, clean-up function that is called at the end of each request|
180+
| `accountId`|optional, aws account id. Placed in ENVIRONMENT|
181+
| `region`|optional, AWS region, default to `us-east-1`. adds AWS_REGION to ENVIRONMENT|
182+
| `profile`|optional, defaults to `default`. profile from `~/.aws/credential` to use. Adds tokens to AWS_TOKEN, AWS_SECRET_TOKEN, AWS_SESSION_TOKEN|
183+
| `credentialsFilename`|optional, defaults to `~/.aws/credential`|
103184
| `logger`|optional, winston Logger object. will default to the console object if not present|
104-
| `defaultHeaders`|optional, headers that should be applied to all responses|
185+
| `defaultResponseHeaders`|optional, headers that should be applied to all responses|
105186

106187

107188
## License

src/devServer.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export interface HandlerConfig extends WrapperOptions {
2222
environment?: HandlerEnvironment;
2323
}
2424

25-
export interface DevServerConfig extends WrapperOptions {
25+
export interface DevServerConfig {
2626
port?: number;
2727
hotReload?: boolean;
2828
prod?: boolean;
@@ -204,6 +204,12 @@ export function getDevServer(config?: DevServerConfig) {
204204
}
205205

206206
export function startDevServer(config: DevServerConfig = {}) {
207+
if (config.prod) {
208+
process.env.NODE_ENV = 'production';
209+
} else if (process.env.NODE_ENV === 'production') {
210+
config.prod = true;
211+
}
212+
207213
const port = config.port ?? 3001;
208214
const hotReload = config.hotReload ?? true;
209215

0 commit comments

Comments
 (0)