Skip to content

Commit 1bbb068

Browse files
committed
* merge with upstream repo
2 parents 305cd15 + 47ce5c9 commit 1bbb068

23 files changed

+3803
-107
lines changed

.npmignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
next_version
1+
manual_test
22
.eslintrc.js
33
.editorconfig

README.md

Lines changed: 135 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Serverless Offline Python Plugin
2+
23
[![serverless](http://public.serverless.com/badges/v3.svg)](http://www.serverless.com)
34
[![npm version](https://badge.fury.io/js/serverless-offline.svg)](https://badge.fury.io/js/serverless-offline)
45
[![Build Status](https://travis-ci.org/dherault/serverless-offline.svg?branch=master)](https://travis-ci.org/dherault/serverless-offline)
@@ -8,26 +9,29 @@ This [Serverless](https://github.com/serverless/serverless) plugin emulates AWS
89
To do so, it starts an HTTP server that handles the request's lifecycle like APIG does and invokes your handlers.
910

1011
**Features:**
11-
- Nodejs λ only.
12-
- Velocity templates support.
13-
- Lazy loading of your files with require cache invalidation: no need for a reloading tool like Nodemon.
14-
- And more: integrations, authorizers, timeouts, responseParameters, HTTPS, Babel runtime, CORS, etc...
12+
13+
* Nodejs λ only.
14+
* Velocity templates support.
15+
* Lazy loading of your files with require cache invalidation: no need for a reloading tool like Nodemon.
16+
* And more: integrations, authorizers, proxies, timeouts, responseParameters, HTTPS, Babel runtime, CORS, etc...
17+
18+
This plugin is updated by its users, I just do maintenance and ensure that PRs are relevant to the community. In other words, if you [find a bug or want a new feature](https://github.com/dherault/serverless-offline/issues), please help us by becoming one of the [contributors](https://github.com/dherault/serverless-offline/graphs/contributors) :v: ! See the [contributing section](#contributing). We are looking for maintainers, see [this issue](https://github.com/dherault/serverless-offline/issues/304).
1519

1620
## Documentation
1721

18-
- [Installation](https://github.com/dherault/serverless-offline#installation)
19-
- [Usage and command line options](https://github.com/dherault/serverless-offline#usage-and-command-line-options)
20-
- [Usage with Babel](https://github.com/dherault/serverless-offline#usage-with-babel)
21-
- [Token Authorizers](https://github.com/dherault/serverless-offline#token-authorizers)
22-
- [Custom authorizers](https://github.com/dherault/serverless-offline#custom-authorizers)
23-
- [AWS API Gateway Features](https://github.com/dherault/serverless-offline#aws-api-gateway-features)
24-
- [Velocity nuances](https://github.com/dherault/serverless-offline#velocity-nuances)
25-
- [Debug process](https://github.com/dherault/serverless-offline#debug-process)
26-
- [Scoped execution](https://github.com/dherault/serverless-offline#scoped-execution)
27-
- [Simulation quality](https://github.com/dherault/serverless-offline#simulation-quality)
28-
- [Credits and inspiration](https://github.com/dherault/serverless-offline#credits-and-inspiration)
29-
- [Contributing](https://github.com/dherault/serverless-offline#contributing)
30-
- [License](https://github.com/dherault/serverless-offline#license)
22+
* [Installation](#installation)
23+
* [Usage and command line options](#usage-and-command-line-options)
24+
* [Usage with Babel](#usage-with-babel)
25+
* [Token authorizers](#token-authorizers)
26+
* [Custom authorizers](#custom-authorizers)
27+
* [AWS API Gateway features](#aws-api-gateway-features)
28+
* [Velocity nuances](#velocity-nuances)
29+
* [Debug process](#debug-process)
30+
* [Scoped execution](#scoped-execution)
31+
* [Simulation quality](#simulation-quality)
32+
* [Credits and inspiration](#credits-and-inspiration)
33+
* [Contributing](#contributing)
34+
* [License](#license)
3135

3236
## Installation
3337

@@ -40,6 +44,7 @@ First, add Serverless Offline to your project:
4044
Then inside your project's `serverless.yml` file add following entry to the plugins section: `serverless-offline`. If there is no plugin section you will need to add it to the file.
4145

4246
It should look something like this:
47+
4348
```YAML
4449
plugins:
4550
- serverless-offline-python
@@ -49,7 +54,7 @@ You can check wether you have successfully installed the plugin by running the s
4954
5055
`serverless`
5156

52-
the console should display *Offline* as one of the plugins now available in your Serverless project.
57+
the console should display _Offline_ as one of the plugins now available in your Serverless project.
5358

5459
## Usage and command line options
5560

@@ -72,13 +77,16 @@ All CLI options are optional:
7277
--region -r The region used to populate your templates. Default: the first region for the first stage found.
7378
--noTimeout -t Disables the timeout feature.
7479
--noEnvironment Turns off loading of your environment variables from serverless.yml. Allows the usage of tools such as PM2 or docker-compose.
80+
--resourceRoutes Turns on loading of your HTTP proxy settings from serverless.yml.
7581
--dontPrintOutput Turns off logging of your lambda outputs in the terminal.
7682
--httpsProtocol -H To enable HTTPS, specify directory (relative to your cwd, typically your project dir) for both cert.pem and key.pem files.
7783
--skipCacheInvalidation -c Tells the plugin to skip require cache invalidation. A script reloading tool like Nodemon might then be needed.
7884
--corsAllowOrigin Used as default Access-Control-Allow-Origin header value for responses. Delimit multiple values with commas. Default: '*'
7985
--corsAllowHeaders Used as default Access-Control-Allow-Headers header value for responses. Delimit multiple values with commas. Default: 'accept,content-type,x-api-key'
8086
--corsDisallowCredentials When provided, the default Access-Control-Allow-Credentials header value will be passed as 'false'. Default: true
81-
--exec "<script>" When provided, a shell script is executed when the server starts up, and the server will shut domn after handling this command.
87+
--exec "<script>" When provided, a shell script is executed when the server starts up, and the server will shut down after handling this command.
88+
--noAuth Turns off all authorizers
89+
--preserveTrailingSlash Used to keep trailing slashes on the request path
8290
```
8391

8492
Any of the CLI options can be added to your `serverless.yml`. For example:
@@ -94,11 +102,11 @@ Options passed on the command line override YAML options.
94102

95103
By default you can send your requests to `http://localhost:3000/`. Please note that:
96104

97-
- You'll need to restart the plugin if you modify your `serverless.yml` or any of the default velocity template files.
98-
- The event object passed to your λs has one extra key: `{ isOffline: true }`. Also, `process.env.IS_OFFLINE` is `true`.
99-
- When no Content-Type header is set on a request, API Gateway defaults to `application/json`, and so does the plugin.
100-
But if you send an `application/x-www-form-urlencoded` or a `multipart/form-data` body with an `application/json` (or no) Content-Type, API Gateway won't parse your data (you'll get the ugly raw as input), whereas the plugin will answer 400 (malformed JSON).
101-
Please consider explicitly setting your requests' Content-Type and using separate templates.
105+
* You'll need to restart the plugin if you modify your `serverless.yml` or any of the default velocity template files.
106+
* The event object passed to your λs has one extra key: `{ isOffline: true }`. Also, `process.env.IS_OFFLINE` is `true`.
107+
* When no Content-Type header is set on a request, API Gateway defaults to `application/json`, and so does the plugin.
108+
But if you send an `application/x-www-form-urlencoded` or a `multipart/form-data` body with an `application/json` (or no) Content-Type, API Gateway won't parse your data (you'll get the ugly raw as input), whereas the plugin will answer 400 (malformed JSON).
109+
Please consider explicitly setting your requests' Content-Type and using separate templates.
102110

103111
## Usage with Babel
104112

@@ -109,6 +117,7 @@ To do so you need to install (at least) the es2015 preset in your project folder
109117

110118
Your λ handlers can be required with `babel-register`.
111119
To do so, in your `serverless.yml` file, set options to be passed to babel-register like this:
120+
112121
```yml
113122
custom:
114123
serverless-offline:
@@ -118,6 +127,41 @@ custom:
118127

119128
Here is the full list of [babel-register options](https://babeljs.io/docs/usage/require/)
120129

130+
## Usage with Flow
131+
132+
If you're using [Flow](https://flow.org/en/) in your service, you'll need to update your `babelOptions` as mentioned [above](#usage-with-babel).
133+
134+
Ensure that `babel-preset-flow` and `transform-flow-strip-types` are installed and properly configured in your project.
135+
136+
```
137+
yarn add -D babel-preset-env babel-preset-flow babel-plugin-transform-runtime babel-plugin-transform-flow-strip-types
138+
```
139+
140+
Then, in your `.babelrc`:
141+
142+
```
143+
{
144+
"presets": [
145+
"env",
146+
"flow"
147+
],
148+
"plugins": [
149+
"transform-runtime",
150+
"transform-flow-strip-types"
151+
]
152+
}
153+
```
154+
155+
See the [docs](https://flow.org/en/docs/install/) for additional details on setting up Flow.
156+
157+
Finally, add the `"flow"` preset to your `babelOptions`:
158+
159+
```yml
160+
custom:
161+
serverless-offline:
162+
babelOptions:
163+
presets: ["env", "flow"]
164+
```
121165

122166
## Token Authorizers
123167

@@ -130,16 +174,19 @@ Serverless-offline will emulate the behaviour of APIG and create a random token
130174
Only [custom authorizers](https://aws.amazon.com/blogs/compute/introducing-custom-authorizers-in-amazon-api-gateway/) are supported. Custom authorizers are executed before a Lambda function is executed and return an Error or a Policy document.
131175

132176
The Custom authorizer is passed an `event` object as below:
177+
133178
```javascript
134179
{
135180
"type": "TOKEN",
136181
"authorizationToken": "<Incoming bearer token>",
137182
"methodArn": "arn:aws:execute-api:<Region id>:<Account id>:<API id>/<Stage>/<Method>/<Resource path>"
138183
}
139184
```
185+
140186
The `methodArn` does not include the Account id or API id.
141187

142188
The plugin only supports retrieving Tokens from headers. You can configure the header as below:
189+
143190
```javascript
144191
"authorizer": {
145192
"type": "TOKEN",
@@ -182,10 +229,47 @@ Works out of the box.
182229
### Lambda and Lambda Proxy Integrations
183230

184231
[Serverless doc](https://serverless.com/framework/docs/providers/aws/events/apigateway#lambda-proxy-integration)
185-
~ [AWS doc](http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html)
232+
~ [AWS doc](http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html)
186233

187234
Works out of the box. See examples in the manual_test directory.
188235

236+
### HTTP Proxy
237+
238+
[Serverless doc](https://serverless.com/framework/docs/providers/aws/events/apigateway#setting-an-http-proxy-on-api-gateway)
239+
~
240+
[AWS doc - AWS::ApiGateway::Method](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-method.html)
241+
~
242+
[AWS doc - AWS::ApiGateway::Resource](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-resource.html)
243+
244+
Example of enabling proxy:
245+
246+
```
247+
custom:
248+
serverless-offline:
249+
resourceRoutes: true
250+
```
251+
252+
or
253+
254+
```
255+
YourCloudFormationMethodId:
256+
Type: AWS::ApiGateway::Method
257+
Properties:
258+
......
259+
Integration:
260+
Type: HTTP_PROXY
261+
Uri: 'https://s3-${self:custom.region}.amazonaws.com/${self:custom.yourBucketName}/{proxy}'
262+
......
263+
```
264+
265+
```
266+
custom:
267+
serverless-offline:
268+
resourceRoutes:
269+
YourCloudFormationMethodId:
270+
Uri: 'http://localhost:3001/assets/{proxy}'
271+
```
272+
189273
### Response parameters
190274

191275
[AWS doc](http://docs.aws.amazon.com/apigateway/latest/developerguide/request-response-data-mappings.html#mapping-response-parameters)
@@ -195,6 +279,7 @@ You can set your response's headers using ResponseParameters.
195279
May not work properly. Please PR. (Difficulty: hard?)
196280

197281
Example response velocity template:
282+
198283
```javascript
199284
"responseParameters": {
200285
"method.response.header.X-Powered-By": "Serverless", // a string
@@ -206,6 +291,7 @@ Example response velocity template:
206291
## Velocity nuances
207292

208293
Consider this requestTemplate for a POST endpoint:
294+
209295
```json
210296
"application/json": {
211297
"payload": "$input.json('$')",
@@ -217,6 +303,7 @@ Consider this requestTemplate for a POST endpoint:
217303
Now let's make a request with this body: `{ "id": 1 }`
218304

219305
AWS parses the event as such:
306+
220307
```javascript
221308
{
222309
"payload": {
@@ -228,6 +315,7 @@ AWS parses the event as such:
228315
```
229316

230317
Whereas Offline parses:
318+
231319
```javascript
232320
{
233321
"payload": {
@@ -246,9 +334,9 @@ You may find other differences.
246334

247335
Serverless offline plugin will respond to the overall framework settings and output additional information to the console in debug mode. In order to do this you will have to set the `SLS_DEBUG` environmental variable. You can run the following in the command line to switch to debug mode execution.
248336

249-
>Unix: `export SLS_DEBUG=*`
337+
> Unix: `export SLS_DEBUG=*`
250338
251-
>Windows: `SET SLS_DEBUG=*`
339+
> Windows: `SET SLS_DEBUG=*`
252340
253341
Interactive debugging is also possible for your project if you have installed the node-inspector module and chrome browser. You can then run the following command line inside your project's root.
254342

@@ -262,6 +350,16 @@ The system will start in wait status. This will also automatically start the chr
262350

263351
Depending on the breakpoint, you may need to call the URL path for your function in seperate browser window for your serverless function to be run and made available for debugging.
264352

353+
## Resource permissions and AWS profile
354+
355+
Lambda functions assume an IAM role during execution: the framework creates this role and set all the permission provided in the `iamRoleStatements` section of `serverless.yml`.
356+
357+
However, serverless offline makes use of your local AWS profile credentials to run the lambda functions and that might result in a different set of permissions. By default, the aws-sdk would load credentials for you default AWS profile specified in your configuration file.
358+
359+
You can change this profile directly in the code or by setting proper environment variables. Setting the `AWS_PROFILE` environment variable before calling `serverless` offline to a different profile would effectively change the credentials, e.g.
360+
361+
`AWS_PROFILE=<profile> serverless offline`
362+
265363
## Scoped execution
266364

267365
Serverless offline plugin can invoke shell scripts when a simulated server has been started up for the purposes of integration testing. Downstream plugins may tie into the
@@ -272,26 +370,25 @@ Serverless offline plugin can invoke shell scripts when a simulated server has b
272370
## Simulation quality
273371

274372
This plugin simulates API Gateway for many practical purposes, good enough for development - but is not a perfect simulator.
275-
Specifically, Lambda currently runs on Node v4.3.2 and v6.10.0, whereas *Offline* runs on your own runtime where no memory limits are enforced.
373+
Specifically, Lambda currently runs on Node v4.3.2 and v6.10.0, whereas _Offline_ runs on your own runtime where no memory limits are enforced.
276374

277375
## Usage with serverless-offline and serverless-webpack plugin
278376

279-
Run `serverless offline start`. In comparison with `serverless offline`, the `start` command will fire an `init` and a `end` lifecycle hook which is needed for serverless-offline and serverless-dynamodb-local to switch off ressources.
280-
281-
Add plugins to your `serverless.yml` file:
282-
```yaml
283-
plugins:
284-
- serverless-webpack
285-
- serverless-dynamodb-local
286-
- serverless-offline #serverless-offline needs to be last in the list
287-
```
377+
Run `serverless offline start`. In comparison with `serverless offline`, the `start` command will fire an `init` and a `end` lifecycle hook which is needed for serverless-offline and serverless-dynamodb-local to switch off ressources.
288378

379+
Add plugins to your `serverless.yml` file:
380+
381+
```yaml
382+
plugins:
383+
- serverless-webpack
384+
- serverless-dynamodb-local
385+
- serverless-offline #serverless-offline needs to be last in the list
386+
```
289387
290388
## Credits and inspiration
291389
292390
This plugin was initially a fork of [Nopik](https://github.com/Nopik/)'s [Serverless-serve](https://github.com/Nopik/serverless-serve).
293391
294-
295392
## Contributing
296393
297394
Yes, thank you!

manual_test/handler.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,22 @@ module.exports.hello = (event, context, callback) => {
1212
callback(null, response);
1313
};
1414

15+
module.exports.rejectedPromise = (event, context, callback) => {
16+
const response = {
17+
statusCode: 200,
18+
body: JSON.stringify({
19+
message: 'Go Serverless v1.0! Your function executed successfully!',
20+
input: event,
21+
}),
22+
};
23+
24+
console.log('About to reject promise');
25+
26+
Promise.reject(new Error('This is the rejected error'));
27+
28+
callback(null, response);
29+
};
30+
1531
module.exports.authFunction = (event, context, callback) => {
1632
context.succeed({
1733
principalId: 'xxxxxxx', // the principal user identification associated with the token send by the client
@@ -70,3 +86,14 @@ module.exports.catchAll = (event, context, cb) => {
7086

7187
cb(null, response);
7288
};
89+
90+
module.exports.pathParams = (event, context, cb) => {
91+
const response = {
92+
statusCode: 200,
93+
body: JSON.stringify({
94+
message: `id is ${event.pathParameters.id}`,
95+
}),
96+
};
97+
98+
cb(null, response);
99+
};

0 commit comments

Comments
 (0)