Skip to content

Commit

Permalink
Merge branch 'release/1.4.0'
Browse files Browse the repository at this point in the history
- Support for proxy request multiValueHeaders
- Support for proxy request multiValueQueryStringParameters
- Support for proxy isBase64Encoded
  • Loading branch information
Ethan Dave B. Gomez committed Mar 11, 2019
2 parents 4460aa0 + 654615b commit dbb99a2
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 123 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 1.4.0

- Support for proxy request multiValueHeaders
- Support for proxy request multiValueQueryStringParameters
- Support for proxy isBase64Encoded

## 1.3.0

- Fix escape
Expand Down
33 changes: 20 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# api-gateway-sim

AWS API Gateway simulator for Node JS Lambda

Install

```bash
$ npm install -g api-gateway-sim
```
Expand All @@ -13,23 +15,27 @@ Choose **"Export as Swagger + API Gateway Integrations"**.
See details in [Export an API from Api Gateway](http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-export-api.html)

Running the simulator using **_ags_** cli

```bash
$ cd <node lambda directory>
$ ags --swagger <exported swagger json file>.json

```

Testing your lambda

```bash
$ curl http://localhost:3000/
```

Using different listening port

```bash
$ PORT=4000 ags --swagger <file>.json
```

Command Line Help

```bash
Usage: ags [options]

Expand All @@ -49,23 +55,24 @@ Command Line Help
-g, --ags-port <port> AGS UI port, default 4000
```

Features
---------
## Features

- Supports Body Mapping Templates
- Supports Body Mapping Template validation.

* Supports Body Mapping Templates
* Supports Body Mapping Template validation.
```bash
$ ags -a

# From your browser open http://localhost:4000
```
* Supports integration responses
* Supports event.json, context.json, and stage-variables.json
* Continues to monitoring changes in your lambda code. YES! No need to restart **_ags_**
* Support for json or yaml swagger file.
* Monitor changes in event.json, context.json, and stage-variables.json
* CORS - enabled by default
* Supports lambda timeout
* Supports base path
* Supports {proxy+}

- Supports integration responses
- Supports event.json, context.json, and stage-variables.json
- Continues to monitoring changes in your lambda code. YES! No need to restart **_ags_**
- Support for json or yaml swagger file.
- Monitor changes in event.json, context.json, and stage-variables.json
- CORS - enabled by default
- Supports lambda timeout
- Supports base path
- Supports {proxy+}
- Supports proxy integration isBase64Encoded, multiValueHeaders, and multiValueQueryStringParameters
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "api-gateway-sim",
"version": "1.3.0",
"version": "1.4.0",
"description": "AWS API Gateway simulator for Node JS Lambda",
"main": "./api-gateway-sim.js",
"bin": {
Expand Down
78 changes: 63 additions & 15 deletions src/api-gateway-sim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,13 +172,6 @@ class ApiGatewaySim {
console.log(message);
}

private getQueryParams(request: Request) {
const url = require('url');
const url_parts = url.parse(request.url, true);
const query = url_parts.query;
return query;
}

private getPassThroughTemplateContent() {
const file = __dirname + '/templates/pass-through.vtl';
return fs.readFileSync(file, 'utf8');
Expand Down Expand Up @@ -290,13 +283,37 @@ class ApiGatewaySim {
}
}

private setHeaders(bodyTemplate: BodyTemplate, request: Request) {
const keys = Object.keys(request.headers);
if (!bodyTemplate.headers) {
bodyTemplate.headers = {};
}
for (const key of keys) {
if (Array.isArray(request.headers[key])) {
bodyTemplate.headers[key] =
request.headers[key][request.headers[key].length - 1];
bodyTemplate.multiValueHeaders[key] = request.headers[key];
} else {
bodyTemplate.headers[key] = request.headers[key];
bodyTemplate.multiValueHeaders[key] = [request.headers[key]];
}
}
}

private setQueryParams(bodyTemplate: BodyTemplate, request: Request) {
const url = require('url');
const url_parts = url.parse(request.url, true);
const query = url_parts.query;
bodyTemplate.queryParams = query;
}

private parseEvent(method: Method, request: Request) {
const bodyTemplate = new BodyTemplate();
bodyTemplate.context = this.getContextJson();
this.setContextDefaults(bodyTemplate.context, request);
bodyTemplate.headers = request.headers;
this.setHeaders(bodyTemplate, request);
bodyTemplate.pathParams = this.getBodyTemplatePathParams(request);
bodyTemplate.queryParams = this.getQueryParams(request);
this.setQueryParams(bodyTemplate, request);
bodyTemplate.method = request.method;
bodyTemplate.payload = this.getBodyTemplatePayload(method, request);
bodyTemplate.stageVariables = this.getStageVariables();
Expand Down Expand Up @@ -434,11 +451,30 @@ class ApiGatewaySim {
return Object.keys(object).length === 0 && object.constructor === Object;
}

private getProxyQueryString(request: Request) {
private setProxyQueryString(event: any, request: Request) {
if (this.isObjectEmpty(request.query)) {
return null;
event.queryStringParameters = null;
event.multiValueQueryStringParameters = null;
return;
}
if (!event.queryStringParameters) {
event.queryStringParameters = {};
}
if (!event.multiValueQueryStringParameters) {
event.multiValueQueryStringParameters = {};
}
const keys = Object.keys(request.query);
const queries = request.query;
for (const key of keys) {
if (Array.isArray(queries[key])) {
event.queryStringParameters[key] =
queries[key][queries[key].length - 1];
event.multiValueQueryStringParameters[key] = queries[key];
} else {
event.queryStringParameters[key] = queries[key];
event.multiValueQueryStringParameters[key] = [queries[key]];
}
}
return request.query;
}

private processProxyData(
Expand All @@ -458,9 +494,7 @@ class ApiGatewaySim {
request.originalUrl
);
requestObject.eventJson.headers = this.getRawHeaders(request);
requestObject.eventJson.queryStringParameters = this.getProxyQueryString(
request
);
this.setProxyQueryString(requestObject.eventJson, request);
requestObject.eventJson.httpMethod = request.method;
this.removeNonProxyFields(requestObject.eventJson);
this.setProxyStageVariables(path, requestObject.eventJson, request);
Expand Down Expand Up @@ -567,6 +601,7 @@ class ApiGatewaySim {
body: true,
statusCode: true,
headers: true,
isBase64Encoded: true,
multiValueHeaders: true
};
for (const property in message) {
Expand Down Expand Up @@ -614,6 +649,16 @@ class ApiGatewaySim {
}
}

private setBase64Encoded(method: Method, message: any) {
if (
method.integration &&
method.integration.contentHandling === 'CONVERT_TO_BINARY'
) {
return Buffer.from(message.body, 'base64');
}
return message.body;
}

private sendAwsProxyResponse(
httpResponse: Response,
method: Method,
Expand All @@ -640,6 +685,9 @@ class ApiGatewaySim {
} else {
this.setMessageStatusCode(httpResponse, message);
this.setMessageHeaders(httpResponse, message);
if (message.isBase64Encoded) {
parseBody = this.setBase64Encoded(method, message);
}
this.sendDefaultResponse(httpResponse, method, parseBody);
}
} catch (error) {
Expand Down
Loading

0 comments on commit dbb99a2

Please sign in to comment.