├── .gitignore
├── .npmignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── example.js
├── index.js
├── misc
├── endpoint.js
├── examples.js
├── gen.js
├── post_examples.js
└── result.js
├── package.json
└── test
├── _.js
├── _.md
├── input.js
├── renderer.js
└── util.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 | package-lock.json
4 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | /examples
2 | /misc
3 | /web
4 | /node_modules
5 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 |
2 | ## [0.0.8](https://github.com/ToQoz/api-gateway-mapping-template/compare/v0.0.7...v0.0.8) (2020-04-29)
3 |
4 |
5 | ### Bug Fixes
6 |
7 | * print null objects as empty string #4
8 |
9 |
10 |
11 |
12 | ## [0.0.7](https://github.com/ToQoz/api-gateway-mapping-template/compare/v0.0.6...v0.0.7) (2015-12-19)
13 |
14 |
15 | ### Bug Fixes
16 |
17 | * **package:** don't escape HTML ([f3c5d99](https://github.com/ToQoz/api-gateway-mapping-template/commit/f3c5d99))
18 | * **readme:** update ([6fab78e](https://github.com/ToQoz/api-gateway-mapping-template/commit/6fab78e))
19 |
20 |
21 |
22 |
23 | ## [0.0.6](https://github.com/ToQoz/api-gateway-mapping-template/compare/v0.0.5...v0.0.6) (2015-12-18)
24 |
25 |
26 | ### Bug Fixes
27 |
28 | * **package:** In $input.json, if payload is empty, treat it as empty object ([0bcb8e2](https://github.com/ToQoz/api-gateway-mapping-template/commit/0bcb8e2))
29 | * **package:** In $input.path, if payload is empty, treat it as empty object ([47cbd78](https://github.com/ToQoz/api-gateway-mapping-template/commit/47cbd78))
30 |
31 |
32 |
33 |
34 | ## [0.0.5](https://github.com/ToQoz/api-gateway-mapping-template/compare/v0.0.4...v0.0.5) (2015-12-18)
35 |
36 |
37 | ### Bug Fixes
38 |
39 | * **package:** fix a bug in $input.json ([fde5289](https://github.com/ToQoz/api-gateway-mapping-template/commit/fde5289))
40 |
41 |
42 |
43 |
44 | ## [0.0.4](https://github.com/ToQoz/api-gateway-mapping-template/compare/v0.0.3...v0.0.4) (2015-12-15)
45 |
46 |
47 | ### Bug Fixes
48 |
49 | * **example:** follow new(v.0.0.3) API ([404742b](https://github.com/ToQoz/api-gateway-mapping-template/commit/404742b))
50 |
51 |
52 |
53 |
54 | ## [0.0.3](https://github.com/ToQoz/api-gateway-mapping-template/compare/v0.0.2...v0.0.3) (2015-12-15)
55 |
56 |
57 | ### Bug Fixes
58 |
59 | * **test:** wait(d).fn -> wait(d).then(fn) ([9652ecb](https://github.com/ToQoz/api-gateway-mapping-template/commit/9652ecb))
60 |
61 | ### Features
62 |
63 | * **package:** change API signature of module.exports ([06b320f](https://github.com/ToQoz/api-gateway-mapping-template/commit/06b320f))
64 |
65 |
66 | ### BREAKING CHANGE
67 |
68 | - module.exports takes `parameters` instead of `template`, `payload`, `params`, `context`
69 |
70 |
71 |
72 |
73 | ## [0.0.2](https://github.com/ToQoz/api-gateway-mapping-template/compare/v0.0.1...v0.0.2) (2015-12-14)
74 |
75 |
76 | ### Bug Fixes
77 |
78 | * **package:** improve workaround for obj.toString ([a45557f](https://github.com/ToQoz/api-gateway-mapping-template/commit/a45557f))
79 |
80 |
81 |
82 |
83 | ## 0.0.1 (2015-12-13)
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Takatoshi Matsumoto
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # api-gateway-mapping-template
2 |
3 | make AWS API Gateway's Mapping Template testable
4 |
5 | 
6 |
7 | ## Installation
8 |
9 | ```
10 | npm install api-gateway-mapping-template
11 | ```
12 |
13 | ## Usage
14 |
15 | simple.js:
16 |
17 | ```node
18 | var mappingTemplate = require('api-gateway-mapping-template')
19 |
20 | var vtl = '$input.json(\'$.data\')';
21 | var payload = '{"data": {"url": "https://github.com/ToQoz/api-gateway-mapping-template"}}';
22 |
23 | var result = mappingTemplate({template: vtl, payload: payload})
24 | console.dir(result);
25 | ```
26 |
27 | ***
28 |
29 | ```
30 | $ node ./simple.js
31 | '{"url":"https://github.com/ToQoz/api-gateway-mapping-template"}'
32 | ```
33 |
34 | ## Examples
35 |
36 | - [ToQoz/api-gateway-localdev](https://github.com/ToQoz/api-gateway-localdev) - simulate API Gateway + Lambda in your local.
37 | - [online checker](https://github.com/ToQoz/mapping-template-checker.toqoz.net) - http://mapping-template-checker.toqoz.net
38 |
39 | ## API
40 |
41 | ```node
42 | var mappingTemplate = require('api-gateway-mapping-template')
43 | ```
44 |
45 | ### mappingTemplate(parameters)
46 |
47 | This function renders AWS API Gateway's Mapping Template by using given payload, params and context.
48 |
49 | - Arguments
50 | - parameters - **required** - `map`
51 | - template - **required** - `String|Buffer`
52 | - payload - **required** - `String|Buffer`
53 | - params - `map`
54 | - path - `map`
55 | - querystring - `map`
56 | - header - `map`
57 | - context - `map`
58 | - indentity - `map`
59 | - cognitoAuthenticationType - `String`
60 | - cognitoIdentityId - `String`
61 | - cognitoIdentityPoolId - `String`
62 | - sourceIp - `String`
63 | - user - `String`
64 | - userAgent - `String`
65 | - userArn - `String`
66 | - requestId - `String`
67 | - resourceId - `String`
68 | - resourcePath - `String`
69 | - stage - `String`
70 | - Return value
71 | - rendered template - `String`
72 |
--------------------------------------------------------------------------------
/example.js:
--------------------------------------------------------------------------------
1 | var mappingTemplate = require('api-gateway-mapping-template');
2 |
3 | var vtl = '$input.json(\'$.data\')';
4 | var payload = '{"data": {"url": "https://github.com/ToQoz/api-gateway-mapping-template"}}';
5 |
6 | var result = mappingTemplate({template: vtl, payload: payload});
7 | console.dir(result);
8 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var clone = require('clone');
2 | var Velocity = require('velocityjs');
3 | var jsonpath = workaroundJsonPath(require('JSONPath'));
4 |
5 | module.exports = function(parameters) {
6 | parameters = clone(parameters || {});
7 |
8 | var template = parameters.template;
9 | var payload = parameters.payload;
10 |
11 | var params = clone(parameters.params || {});
12 | params.path = params.path || {};
13 | params.querystring = params.querystring || {};
14 | params.header = params.header || {};
15 |
16 | var context = clone(parameters.context || {});
17 | context.identity = context.identity || {};
18 |
19 | // API Gateway Mapping Template Reference
20 | // http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html
21 | var data = {
22 | context: context,
23 | input: {
24 | _payload: payload.toString(),
25 | path: function(path) {
26 | var obj;
27 | if (this._payload === '') {
28 | // if payload is empty, treat it as empty object
29 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-91575d0e
30 | obj = {};
31 | } else if (/^\s*(?:{|\[|")/.test(this._payload)) {
32 | // if payload starts with `{` or `[` or `"`, treat as JSON
33 | obj = JSON.parse(this._payload);
34 | } else {
35 | // treat as string
36 | obj = this._payload;
37 | }
38 |
39 | return jsonpath(obj, path);
40 | },
41 | json: function(path) {
42 | var obj;
43 | if (this._payload === '') {
44 | // if payload is empty, treat it as empty object
45 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-098fd028
46 | obj = {};
47 | } else if (/^\s*(?:{|\[|")/.test(this._payload)) {
48 | // if payload starts with `{` or `[` or `"`, treat as JSON
49 | obj = JSON.parse(this._payload);
50 | } else {
51 | // treat as string
52 | obj = this._payload;
53 | }
54 |
55 | return JSON.stringify(jsonpath(obj, path));
56 | },
57 | params: function(x) {
58 | switch (true) {
59 | case x === undefined:
60 | return params;
61 | case x in params.path:
62 | return params.path[x];
63 | case x in params.querystring:
64 | return params.querystring[x];
65 | case x in params.header:
66 | return params.header[x];
67 | }
68 | },
69 | },
70 | util: {
71 | escapeJavaScript: escapeJavaScript,
72 | urlEncode: encodeURIComponent,
73 | urlDecode: decodeURIComponent,
74 | base64Encode: base64Encode,
75 | base64Decode: base64Decode,
76 | }
77 | };
78 |
79 | data = workaroundAwsObjectSerialization(data);
80 |
81 | var ast = Velocity.parse(template.toString());
82 | var config = {
83 | escape: false, // don't escape HTML
84 | };
85 | return (new Velocity.Compile(ast, config)).render(data, null, true);
86 | };
87 |
88 | // Workaround to followings
89 | // When the tempalte is "$input.params" (is a Function)
90 | // - AWS API Gateway returns "{}".
91 | // - This is not org.apache.velocity's behaviour. It returns "$input.params".
92 | // When the tempalte is "$input" or "$util"
93 | // - AWS API Gateway returns "{}"
94 | // - This is not org.apache.velocity's behaviour. It returns serialized hash.
95 | function workaroundAwsObjectSerialization(data) {
96 | var returnEmptyObject = function() { return "{}"; };
97 |
98 | // This never be called because keySet/entrySet/size will be processed by velocity.js.
99 | // But I want to handling only toString
100 | var builtinMethod = function() { throw "unexpected error"; };
101 | builtinMethod.toString = returnEmptyObject;
102 |
103 | data.input.toString = returnEmptyObject;
104 | data.util.toString = returnEmptyObject;
105 | walk(data, function(obj) {
106 | if (typeof(obj) == 'function') {
107 | obj.toString = returnEmptyObject;
108 | }
109 |
110 | obj.keySet = builtinMethod;
111 | obj.entrySet = builtinMethod;
112 | obj.size = builtinMethod;
113 | });
114 |
115 | return data;
116 | }
117 |
118 | function workaroundJsonPath(jsonpath) {
119 | return function(obj, path) {
120 | if (path === '$') {
121 | return obj;
122 | }
123 |
124 | var result = jsonpath({
125 | json: obj,
126 | path: path
127 | });
128 |
129 | if (result.length === 1) {
130 | return result[0];
131 | } else {
132 | return result;
133 | }
134 | };
135 | }
136 |
137 | function walk(obj, cb) {
138 | cb(obj);
139 |
140 | if (Array.isArray(obj)) {
141 | obj.forEach(function(c) {
142 | walk(c, cb);
143 | });
144 | } else if ({}.toString.call(obj) === '[object Object]') {
145 | Object.keys(obj).forEach(function(k) {
146 | walk(obj[k], cb);
147 | });
148 | }
149 | }
150 |
151 | function base64Encode(x) {
152 | return (new Buffer(x)).toString('base64');
153 | }
154 |
155 | function base64Decode(x) {
156 | return (new Buffer(x, 'base64')).toString();
157 | }
158 |
159 | // I recognize $util.escapeJavaScript as almost `escapeJSONString` and implemented so.
160 | // c.f. 24.3.2.2 Runtime Semantics: QuoteJSONString ( value )
161 | // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-quotejsonstring
162 | // DO: 2.a -> 2.b -> 2.c -> 2.d
163 | var escapeJavaScriptTable = {
164 | '"': '\"', // 2.a
165 | '\\': '\\\\',
166 | '\b': '\\b', // 2.b (skip abbrev)
167 | '\f': '\\f',
168 | '\n': '\\n',
169 | '\r': '\\r',
170 | '\t': '\\t',
171 | };
172 | // 2.c
173 | for (var code = 0; code < 20; code++) {
174 | escapeJavaScriptTable[String.fromCharCode(code)] = ((code < 16) ? '\\u000' : '\\u00') + code.toString(16);
175 | }
176 | function escapeJavaScript(x) {
177 | return x.split("").map(function(c) {
178 | // 2.a - 2.c
179 | if (c in escapeJavaScriptTable) {
180 | return escapeJavaScriptTable[c];
181 | }
182 |
183 | // 2.d
184 | return c;
185 | }).join("");
186 | }
187 |
--------------------------------------------------------------------------------
/misc/endpoint.js:
--------------------------------------------------------------------------------
1 | var AWS = require('aws-sdk');
2 | var lambda = new AWS.Lambda();
3 | var apiGateway = new AWS.APIGateway();
4 |
5 | var Promise = require('bluebird');
6 | Promise.promisifyAll(Object.getPrototypeOf(apiGateway));
7 |
8 | module.exports = Endpoint;
9 |
10 | function Endpoint(params) {
11 | this.region = params.region;
12 | this.accountId = params.accountId;
13 |
14 | this.apiName = params.apiName;
15 | this.restApiId = null;
16 | this.resourceId = null;
17 | this.lambdaRole = params.lambdaRole;
18 | this.functionName = params.functionName;
19 | this.functionZip = params.functionZip;
20 | this.functionArn = null;
21 | this.httpMethod = "POST";
22 |
23 | this._defer = [];
24 |
25 | this.promise = Promise.resolve();
26 | }
27 |
28 | Endpoint.prototype.defer = function(cb) {
29 | this._defer = this._defer || [];
30 | this._defer.push(cb);
31 | };
32 |
33 | Endpoint.prototype.cleanup = function() {
34 | console.log("cleanup...");
35 | while(true) {
36 | if (!this._defer || this._defer <= 0) break;
37 | this._defer.pop()();
38 | }
39 | };
40 |
41 | Endpoint.prototype.then = function (onFulfilled, onRejected) {
42 | this.promise = this.promise.then(onFulfilled, onRejected);
43 | return this;
44 | };
45 |
46 | Endpoint.prototype["catch"] = function (onRejected) {
47 | this.promise = this.promise.catch(onRejected);
48 | return this;
49 | };
50 |
51 | Endpoint.prototype.createFunction = function() {
52 | var that = this;
53 |
54 | return this.then(function() {
55 | console.log("create function");
56 |
57 | return new Promise(function(resolve, reject) {
58 | lambda.createFunction(
59 | {
60 | FunctionName: that.functionName,
61 | Runtime: "nodejs",
62 | Role: that.lambdaRole,
63 | Handler: 'index.handler',
64 | Timeout: 6,
65 | MemorySize: 128,
66 | Code: {
67 | ZipFile: that.functionZip.toBuffer()
68 | }
69 | },
70 | function(err, data) {
71 | if (err) {
72 | reject(err);
73 | } else {
74 | resolve(data);
75 | }
76 | }
77 | );
78 | })
79 | .then(function(data) {
80 | that.functionArn = data.FunctionArn;
81 | that.defer(function() {
82 | console.log("delete lambda functionName=" + that.functionName);
83 | lambda.deleteFunction({FunctionName: that.functionName}, function(err) { if (err) console.log(err); });
84 | });
85 | });
86 | });
87 | };
88 |
89 | Endpoint.prototype.createRestApi = function() {
90 | var that = this;
91 |
92 | return this.then(function() {
93 | console.log("create rest api");
94 | return apiGateway.createRestApiAsync({name: that.apiName})
95 | .then(function(data) {
96 | that.restApiId = data.id;
97 | that.endpoint_url = "https://" + that.restApiId + ".execute-api." + that.region + ".amazonaws.com/dev";
98 |
99 | that.defer(function() {
100 | console.log("delete api restApiId=" + that.restApiId);
101 | apiGateway.deleteRestApiAsync({restApiId: that.restApiId});
102 | });
103 |
104 | console.log("get resources");
105 | return apiGateway.getResourcesAsync({restApiId: that.restApiId})
106 | .then(function(data) {
107 | var rootResourceId = data.items[0].id;
108 | that.resourceId = rootResourceId;
109 | });
110 | });
111 | });
112 | };
113 |
114 | Endpoint.prototype.putMethod = function() {
115 | var that = this;
116 |
117 | return this.then(function() {
118 | console.log("add put method");
119 | return apiGateway.putMethodAsync({
120 | restApiId: that.restApiId,
121 | resourceId: that.resourceId,
122 | httpMethod: that.httpMethod,
123 | authorizationType: 'None',
124 | apiKeyRequired: false,
125 | requestParameters: {}
126 | });
127 | });
128 | };
129 |
130 | Endpoint.prototype.putIntegration = function(requestTemplates) {
131 | var that = this;
132 |
133 | return this.then(function() {
134 | console.log("add put integration");
135 |
136 | return apiGateway.putIntegrationAsync({
137 | restApiId: that.restApiId,
138 | resourceId: that.resourceId,
139 | httpMethod: that.httpMethod,
140 | integrationHttpMethod: "POST",
141 | type: "AWS",
142 | requestTemplates: requestTemplates,
143 | uri: "arn:aws:apigateway:" + that.region + ":lambda:path/2015-03-31/functions/" + that.functionArn + "/invocations"
144 | });
145 | });
146 | };
147 |
148 | Endpoint.prototype.putMethodResponse = function(responseModels) {
149 | var that = this;
150 |
151 | return this.then(function() {
152 | console.log("add put integration response");
153 |
154 | return Promise.all([200, 400].map(function(code) {
155 | return apiGateway.putMethodResponseAsync({
156 | restApiId: that.restApiId,
157 | resourceId: that.resourceId,
158 | httpMethod: "POST",
159 | statusCode: code.toString(),
160 | responseModels: responseModels
161 | });
162 | }));
163 | });
164 | };
165 |
166 | Endpoint.prototype.putIntegrationResponse = function(responseTemplates) {
167 | var that = this;
168 |
169 | return this.then(function() {
170 | console.log("add put integration response");
171 | return apiGateway.putIntegrationResponseAsync({
172 | restApiId: that.restApiId,
173 | resourceId: that.resourceId,
174 | httpMethod: "POST",
175 | statusCode: "200",
176 | responseTemplates: responseTemplates
177 | });
178 | });
179 | };
180 |
181 | Endpoint.prototype.addPermissionInvokeFunction = function() {
182 | var that = this;
183 |
184 | return this.then(function() {
185 | console.log("add permission");
186 | return new Promise(function(resolve, reject) {
187 | lambda.addPermission(
188 | {
189 | FunctionName: that.functionName,
190 | StatementId: "sid-agmt-" + (Date.now()),
191 | Action: "lambda:InvokeFunction",
192 | Principal: "apigateway.amazonaws.com",
193 | SourceArn: "arn:aws:execute-api:ap-northeast-1:" + that.accountId + ":" + that.restApiId + "/*/POST/",
194 | },
195 | function(err, data) {
196 | if (err) {
197 | reject(err);
198 | } else {
199 | resolve(data);
200 | }
201 | }
202 | );
203 | });
204 | });
205 | };
206 |
207 | Endpoint.prototype.deploy = function() {
208 | var that = this;
209 |
210 | return this.then(function() {
211 | console.log("deploy endpoint");
212 | return apiGateway.createDeploymentAsync({
213 | restApiId: that.restApiId,
214 | stageName: "dev"
215 | });
216 | });
217 | };
218 |
--------------------------------------------------------------------------------
/misc/examples.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | {
3 | template: '"$input.path(\'$\')"',
4 | payload: "a=b",
5 | headers: {},
6 | },
7 | {
8 | template: '"$input.path(\'$\')"',
9 | payload: '"a=b"',
10 | headers: {},
11 | },
12 | {
13 | template: '$input.json(\'$\')',
14 | payload: "a=b",
15 | headers: {},
16 | },
17 | {
18 | template: '$input.json(\'$\')',
19 | payload: '"a=b"',
20 | headers: {},
21 | },
22 | {
23 | template: '"$input.path(\'$\')"',
24 | payload: "{}",
25 | headers: {},
26 | },
27 | {
28 | template: '"$input.path(\'$\')"',
29 | payload: '"{}"',
30 | headers: {},
31 | },
32 | {
33 | template: '$input.json(\'$\')',
34 | payload: "{}",
35 | headers: {},
36 | },
37 | {
38 | template: '$input.json(\'$\')',
39 | payload: "",
40 | headers: {},
41 | },
42 | {
43 | template: '$input.path(\'$\')',
44 | payload: "",
45 | headers: {},
46 | },
47 | {
48 | template: '{"name": "$input.path(\'$\')"}',
49 | payload: "name=toqoz",
50 | headers: {},
51 | },
52 | {
53 | template: '"$input.path(\'$\')"',
54 | payload: "{a",
55 | headers: {},
56 | },
57 | {
58 | template: '"$input.path(\'$\')"',
59 | payload: "a{b",
60 | headers: {},
61 | },
62 | {
63 | template: '"$input.path(\'$\')"',
64 | payload: "[a",
65 | headers: {},
66 | },
67 | {
68 | template: '"$input.path(\'$\')"',
69 | payload: "a[",
70 | headers: {},
71 | },
72 | {
73 | template: '"$input.path(\'$\')"',
74 | payload: "null{",
75 | headers: {},
76 | },
77 | {
78 | template: '"$input.path(\'$\')"',
79 | payload: "true{",
80 | headers: {},
81 | },
82 | {
83 | template: '"$input.path(\'$\')"',
84 | payload: "false{",
85 | headers: {},
86 | },
87 | {
88 | template: '"$input.path(\'$\')"',
89 | payload: "undefined{",
90 | headers: {},
91 | },
92 | {
93 | template: '$input',
94 | payload: "",
95 | headers: {},
96 | },
97 | {
98 | template: '$input.keySet',
99 | payload: "",
100 | headers: {},
101 | },
102 | {
103 | template: '$input.params.keySet',
104 | payload: "",
105 | headers: {},
106 | },
107 | {
108 | template: '$util',
109 | payload: "",
110 | headers: {},
111 | },
112 | {
113 | template: '$input.params',
114 | payload: "",
115 | headers: {},
116 | },
117 | {
118 | template: '$input.json',
119 | payload: "",
120 | headers: {},
121 | },
122 | {
123 | template: '$util.urlEncode',
124 | payload: "",
125 | headers: {},
126 | },
127 | ];
128 |
--------------------------------------------------------------------------------
/misc/gen.js:
--------------------------------------------------------------------------------
1 | var PRODUCT_NAME="api-gateway-mapping-template-integration-test";
2 |
3 | if (!process.env.AWS_ACCOUNT_ID) {
4 | throw "process.env.AWS_ACCOUNT_ID is required";
5 | }
6 |
7 | process.env.AWS_REGION = process.env.AWS_REGION || "ap-northeast-1";
8 | process.env.AWS_PROFILE = process.env.AWS_PROFILE || PRODUCT_NAME;
9 | process.env.LAMBDA_ROLE = process.env.LAMBDA_ROLE || "arn:aws:iam::" + process.env.AWS_ACCOUNT_ID + ":role/" + PRODUCT_NAME;
10 |
11 | var Promise = require('bluebird');
12 | var Zip = require('adm-zip');
13 |
14 | var Endpoint = require('./endpoint');
15 | var postExamples = require('./post_examples');
16 | var writeResults = require('./result');
17 |
18 |
19 | var zip = new Zip();
20 | zip.addFile('index.js', new Buffer("exports.handler = function(event, context) { context.succeed(JSON.stringify(event)); };"));
21 |
22 | var examples = require('./examples');
23 | var requestTemplates = examples.reduce(function(product, e, i) { product["text/test-" + i] = e.template; return product; }, {});
24 | var responseModels = examples.reduce(function(product, e, i) { product["text/test-" + i] = "Empty"; return product; }, {});
25 | var responseTemplates = examples.reduce(function(product, e, i) { product["text/test-" + i] = "$input.path('$')"; return product; }, {});
26 |
27 | var endpoint = new Endpoint({
28 | region: process.env.AWS_REGION,
29 | accountId: process.env.AWS_ACCOUNT_ID,
30 | apiName: PRODUCT_NAME,
31 | lambdaRole: process.env.LAMBDA_ROLE,
32 | functionName: PRODUCT_NAME + "-console-log",
33 | functionZip: zip
34 | });
35 |
36 | endpoint
37 | .createFunction()
38 | .createRestApi()
39 | .putMethod()
40 | .putIntegration(requestTemplates)
41 | .putMethodResponse(responseModels)
42 | .putIntegrationResponse(responseTemplates)
43 | .addPermissionInvokeFunction()
44 | .deploy()
45 | .then(function() {
46 | console.log(endpoint.endpoint_url);
47 | return postExamples(endpoint.endpoint_url, examples);
48 | })
49 | .then(writeResults)
50 | .then(function() {
51 | endpoint.cleanup();
52 | })
53 | .catch(function(err) {
54 | console.error(err);
55 | err.stack.split('\n').forEach(function(t) { console.error(t); });
56 | endpoint.cleanup();
57 | });
58 |
--------------------------------------------------------------------------------
/misc/post_examples.js:
--------------------------------------------------------------------------------
1 | var http = require('https');
2 | var parseUrl = require('url').parse;
3 | var Promise = require('bluebird');
4 |
5 | module.exports = function (url, examples) {
6 | var q = examples.map(function(ex, i) {
7 | var req = function() { return post(url, extend({}, ex.headers, {'Content-Type': "text/test-" + i}), ex.payload); };
8 | return req()
9 | .then(function(res) {
10 | if (res.statusCode === 500) {
11 | return wait(1000)().then(req);
12 | }
13 |
14 | res.headers = ex.headers;
15 | res.template = ex.template;
16 | res.payload = ex.payload;
17 | return res;
18 | });
19 | });
20 |
21 | return Promise.all(q);
22 | };
23 |
24 | function post(url, headers, data) {
25 | return new Promise(function(resolve, reject) {
26 | var u = parseUrl(url);
27 |
28 | var options = {
29 | hostname: u.hostname,
30 | port: 443,
31 | path: u.path,
32 | method: 'POST',
33 | headers: headers
34 | };
35 |
36 | var req = http.request(options, function(res) {
37 | res.setEncoding('utf8');
38 |
39 | var responseBody = '';
40 |
41 | res.on('data', function (chunk) {
42 | responseBody += chunk;
43 | });
44 |
45 | res.on('end', function() {
46 | resolve({
47 | statusCode: res.statusCode,
48 | headers: res.headers,
49 | body: responseBody
50 | });
51 | });
52 |
53 | req.on('error', function(err) {
54 | reject(err);
55 | });
56 | });
57 |
58 | req.setTimeout(5 * 1000, function() {
59 | reject("timeout: POST " + url);
60 | });
61 |
62 | req.write(data);
63 | req.end();
64 | });
65 | }
66 |
67 | function wait(delay) {
68 | return function() {
69 | return new Promise(function(resolve) {
70 | setTimeout(function() { resolve(); }, delay);
71 | });
72 | };
73 | }
74 |
75 | function extend(target) {
76 | var sources = [].slice.call(arguments, 1);
77 | sources.forEach(function (source) {
78 | for (var prop in source) {
79 | target[prop] = source[prop];
80 | }
81 | });
82 | return target;
83 | }
84 |
--------------------------------------------------------------------------------
/misc/result.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var crypto = require('crypto');
3 |
4 | var sprintf = require("sprintf-js").sprintf;
5 | var Promise = require('bluebird');
6 |
7 | module.exports = function(results) {
8 | return new Promise(function(resolve, reject) {
9 | var testOut = process.env.TEST ? fs.createWriteStream(process.env.TEST) : process.stdout;
10 | var markdownOut = process.env.MD ? fs.createWriteStream(process.env.MD) : process.stdout;
11 |
12 | results = results.map(function(result) {
13 | var r = new Result();
14 | r.mappingTemplate = result.template;
15 | r.requestBody = result.payload;
16 | r.requestHeaders = result.headers;
17 | r.statusCode = result.statusCode;
18 | r.responseBody = result.body;
19 | return r;
20 | });
21 |
22 | // write markdown
23 | results.forEach(function(r, i) {
24 | markdownOut.write(sprintf("## example-%s\n", hash(JSON.stringify(r))));
25 | r.toMarkdown(markdownOut);
26 | });
27 |
28 | // write test
29 | testOut.write(sprintf("// This file is generated by `TEST=%s node misc/gen.js`\n", process.env.TEST));
30 | testOut.write("\n");
31 | testOut.write("var assert = require('assert')\n");
32 | testOut.write("var mappingTemplate = require('../')\n");
33 | testOut.write("\n");
34 | testOut.write("describe('$input.path|$input.json', function() {\n");
35 |
36 | var mdUrl = "https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md";
37 | results.forEach(function(r, i) {
38 | testOut.write(sprintf(" // %s#example-%s\n", mdUrl, hash(JSON.stringify(r))));
39 | r.toTest(testOut, 1);
40 | });
41 |
42 | testOut.write("});");
43 |
44 | resolve();
45 | });
46 | };
47 |
48 | function Result() {
49 | this.mappingTemplate = null;
50 | this.requestBody = null;
51 | this.requestHeaders = null;
52 | this.statusCode = null;
53 | this.responseBody = null;
54 | }
55 |
56 | Result.prototype.toMarkdown = function(out) {
57 | var s = "";
58 | var header = Object.keys(this.requestHeaders).map(function(k) { return k + " : " + this.requestHeaders[k]; }.bind(this)).join("\n");
59 |
60 | var h = ["Template", "Header", "Payload", "Status code", "Result"];
61 | s += h.join("|") + "\n";
62 | s += h.map(function(v) { return v.replace(/./g, "-"); }).join("|") + "\n";
63 |
64 | s += [
65 | "`" + this.mappingTemplate + "`",
66 | "`" + (header || "None") + "`",
67 | "`" + this.requestBody + "`",
68 | "`" + this.statusCode + "`",
69 | "`" + this.responseBody + "`",
70 | ].join("|");
71 |
72 | out.write(s);
73 | out.write("\n\n");
74 | };
75 |
76 | Result.prototype.toTest = function(out, indentLevel) {
77 | var indent = "";
78 | for (var i = 0; i < indentLevel; i++) {
79 | indent += " ";
80 | }
81 |
82 | if (this.statusCode !== 200 || this.responseBody.indexOf("{errorMessage=Unable") === 0) {
83 | out.write(sprintf(indent + "describe('H=`%s` P=`%s` ===> T=`%s`', function() {\n", JSON.stringify(this.requestHeaders).replace(/'/g, "\\'"), this.requestBody.replace(/'/g, "\\'"), this.mappingTemplate.replace(/'/g, "\\'")));
84 | out.write(indent + " it('throw error', function() {\n");
85 | out.write(sprintf(indent + " assert.throws(function() { mappingTemplate({template: %s, payload: %s}); });\n", JSON.stringify(this.mappingTemplate), JSON.stringify(this.requestBody)));
86 | out.write( indent + " });\n");
87 | out.write( indent + "});\n");
88 | } else {
89 | out.write(sprintf(indent + "describe('H=`%s` P=`%s` ===> T=`%s`', function() {\n", JSON.stringify(this.requestHeaders).replace(/'/g, "\\'"), this.requestBody.replace(/'/g, "\\'"), this.mappingTemplate.replace(/'/g, "\\'")));
90 | out.write(sprintf(indent + " it('return %s', function() {\n", this.requestBody.replace(/'/g, "\\'")));
91 | out.write(sprintf(indent + " var expected = %s;\n", this.responseBody));
92 | out.write(sprintf(indent + " var actual = JSON.parse(mappingTemplate({template: %s, payload: %s}));\n", JSON.stringify(this.mappingTemplate), JSON.stringify(this.requestBody)));
93 | out.write( indent + " assert.deepEqual(expected, actual);\n");
94 | out.write( indent + " });\n");
95 | out.write( indent + "});\n");
96 | }
97 | };
98 |
99 | function hash(input) {
100 | var sha1 = crypto.createHash('sha1');
101 | sha1.update(input);
102 | return sha1.digest('hex').slice(0, 8);
103 | }
104 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "api-gateway-mapping-template",
3 | "version": "0.0.8",
4 | "description": "Make AWS API Gateway's Mapping Template testable.",
5 | "repository": {
6 | "type": "git",
7 | "url": "http://github.com/ToQoz/api-gateway-mapping-template.git"
8 | },
9 | "main": "index.js",
10 | "dependencies": {
11 | "JSONPath": "^0.11.2",
12 | "clone": "^1.0.2",
13 | "velocityjs": "^0.7.4"
14 | },
15 | "devDependencies": {
16 | "adm-zip": "^0.4.7",
17 | "api-gateway-mapping-template": "./",
18 | "aws-sdk": "^2.2.22",
19 | "bluebird": "^3.0.6",
20 | "conventional-changelog": "^0.5.1",
21 | "conventional-github-releaser": "^0.5.0",
22 | "express": "^4.13.3",
23 | "mocha": "^2.3.4",
24 | "sprintf-js": "^1.0.3",
25 | "testling": "^1.7.1"
26 | },
27 | "scripts": {
28 | "test": "mocha",
29 | "gen": "TEST=test/_.js MD=test/_.md node misc/gen.js",
30 | "changelog": "conventional-changelog -p angular -i CHANGELOG.md -w",
31 | "gh-release": "conventional-github-releaser -p angular"
32 | },
33 | "license": "MIT",
34 | "author": {
35 | "name": "Takatoshi Matsumoto",
36 | "email": "toqoz403@gmail.com",
37 | "url": "http://toqoz.net"
38 | },
39 | "tonicExampleFilename": "./example.js",
40 | "testling": {
41 | "harness": "mocha-bdd",
42 | "files": "test/*.js",
43 | "browsers": [
44 | "ie/6..latest",
45 | "chrome/22..latest",
46 | "firefox/16..latest",
47 | "safari/latest",
48 | "opera/11.0..latest",
49 | "iphone/6..latest",
50 | "ipad/6..latest",
51 | "android-browser/latest"
52 | ]
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/test/_.js:
--------------------------------------------------------------------------------
1 | // This file is generated by `TEST=test/_.js node misc/gen.js`
2 |
3 | var assert = require('assert')
4 | var mappingTemplate = require('../')
5 |
6 | describe('$input.path|$input.json', function() {
7 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-12f77fd5
8 | describe('H=`{}` P=`a=b` ===> T=`"$input.path(\'$\')"`', function() {
9 | it('return a=b', function() {
10 | var expected = "a=b";
11 | var actual = JSON.parse(mappingTemplate({template: "\"$input.path('$')\"", payload: "a=b"}));
12 | assert.deepEqual(expected, actual);
13 | });
14 | });
15 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-fcaf7ddd
16 | describe('H=`{}` P=`"a=b"` ===> T=`"$input.path(\'$\')"`', function() {
17 | it('return "a=b"', function() {
18 | var expected = "a=b";
19 | var actual = JSON.parse(mappingTemplate({template: "\"$input.path('$')\"", payload: "\"a=b\""}));
20 | assert.deepEqual(expected, actual);
21 | });
22 | });
23 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-0dce6fa3
24 | describe('H=`{}` P=`a=b` ===> T=`$input.json(\'$\')`', function() {
25 | it('return a=b', function() {
26 | var expected = "a=b";
27 | var actual = JSON.parse(mappingTemplate({template: "$input.json('$')", payload: "a=b"}));
28 | assert.deepEqual(expected, actual);
29 | });
30 | });
31 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-dbd6cf1c
32 | describe('H=`{}` P=`"a=b"` ===> T=`$input.json(\'$\')`', function() {
33 | it('return "a=b"', function() {
34 | var expected = "a=b";
35 | var actual = JSON.parse(mappingTemplate({template: "$input.json('$')", payload: "\"a=b\""}));
36 | assert.deepEqual(expected, actual);
37 | });
38 | });
39 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-03be1e25
40 | describe('H=`{}` P=`{}` ===> T=`"$input.path(\'$\')"`', function() {
41 | it('return {}', function() {
42 | var expected = "{}";
43 | var actual = JSON.parse(mappingTemplate({template: "\"$input.path('$')\"", payload: "{}"}));
44 | assert.deepEqual(expected, actual);
45 | });
46 | });
47 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-1b8d22cd
48 | describe('H=`{}` P=`"{}"` ===> T=`"$input.path(\'$\')"`', function() {
49 | it('return "{}"', function() {
50 | var expected = "{}";
51 | var actual = JSON.parse(mappingTemplate({template: "\"$input.path('$')\"", payload: "\"{}\""}));
52 | assert.deepEqual(expected, actual);
53 | });
54 | });
55 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-b9f18c27
56 | describe('H=`{}` P=`{}` ===> T=`$input.json(\'$\')`', function() {
57 | it('return {}', function() {
58 | var expected = {};
59 | var actual = JSON.parse(mappingTemplate({template: "$input.json('$')", payload: "{}"}));
60 | assert.deepEqual(expected, actual);
61 | });
62 | });
63 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-098fd028
64 | describe('H=`{}` P=`` ===> T=`$input.json(\'$\')`', function() {
65 | it('return ', function() {
66 | var expected = {};
67 | var actual = JSON.parse(mappingTemplate({template: "$input.json('$')", payload: ""}));
68 | assert.deepEqual(expected, actual);
69 | });
70 | });
71 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-91575d0e
72 | describe('H=`{}` P=`` ===> T=`$input.path(\'$\')`', function() {
73 | it('return ', function() {
74 | var expected = {};
75 | var actual = JSON.parse(mappingTemplate({template: "$input.path('$')", payload: ""}));
76 | assert.deepEqual(expected, actual);
77 | });
78 | });
79 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-25c6993c
80 | describe('H=`{}` P=`name=toqoz` ===> T=`{"name": "$input.path(\'$\')"}`', function() {
81 | it('return name=toqoz', function() {
82 | var expected = {"name":"name=toqoz"};
83 | var actual = JSON.parse(mappingTemplate({template: "{\"name\": \"$input.path('$')\"}", payload: "name=toqoz"}));
84 | assert.deepEqual(expected, actual);
85 | });
86 | });
87 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-122ff6ce
88 | describe('H=`{}` P=`{a` ===> T=`"$input.path(\'$\')"`', function() {
89 | it('throw error', function() {
90 | assert.throws(function() { mappingTemplate({template: "\"$input.path('$')\"", payload: "{a"}); });
91 | });
92 | });
93 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-d4719b3d
94 | describe('H=`{}` P=`a{b` ===> T=`"$input.path(\'$\')"`', function() {
95 | it('return a{b', function() {
96 | var expected = "a{b";
97 | var actual = JSON.parse(mappingTemplate({template: "\"$input.path('$')\"", payload: "a{b"}));
98 | assert.deepEqual(expected, actual);
99 | });
100 | });
101 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-2b1f2df4
102 | describe('H=`{}` P=`[a` ===> T=`"$input.path(\'$\')"`', function() {
103 | it('throw error', function() {
104 | assert.throws(function() { mappingTemplate({template: "\"$input.path('$')\"", payload: "[a"}); });
105 | });
106 | });
107 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-c0cfe50d
108 | describe('H=`{}` P=`a[` ===> T=`"$input.path(\'$\')"`', function() {
109 | it('return a[', function() {
110 | var expected = "a[";
111 | var actual = JSON.parse(mappingTemplate({template: "\"$input.path('$')\"", payload: "a["}));
112 | assert.deepEqual(expected, actual);
113 | });
114 | });
115 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-a7361ae0
116 | describe('H=`{}` P=`null{` ===> T=`"$input.path(\'$\')"`', function() {
117 | it('return null{', function() {
118 | var expected = "null{";
119 | var actual = JSON.parse(mappingTemplate({template: "\"$input.path('$')\"", payload: "null{"}));
120 | assert.deepEqual(expected, actual);
121 | });
122 | });
123 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-728fbd1f
124 | describe('H=`{}` P=`true{` ===> T=`"$input.path(\'$\')"`', function() {
125 | it('return true{', function() {
126 | var expected = "true{";
127 | var actual = JSON.parse(mappingTemplate({template: "\"$input.path('$')\"", payload: "true{"}));
128 | assert.deepEqual(expected, actual);
129 | });
130 | });
131 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-461fd8fa
132 | describe('H=`{}` P=`false{` ===> T=`"$input.path(\'$\')"`', function() {
133 | it('return false{', function() {
134 | var expected = "false{";
135 | var actual = JSON.parse(mappingTemplate({template: "\"$input.path('$')\"", payload: "false{"}));
136 | assert.deepEqual(expected, actual);
137 | });
138 | });
139 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-48665148
140 | describe('H=`{}` P=`undefined{` ===> T=`"$input.path(\'$\')"`', function() {
141 | it('return undefined{', function() {
142 | var expected = "undefined{";
143 | var actual = JSON.parse(mappingTemplate({template: "\"$input.path('$')\"", payload: "undefined{"}));
144 | assert.deepEqual(expected, actual);
145 | });
146 | });
147 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-cd963d7c
148 | describe('H=`{}` P=`` ===> T=`$input`', function() {
149 | it('return ', function() {
150 | var expected = {};
151 | var actual = JSON.parse(mappingTemplate({template: "$input", payload: ""}));
152 | assert.deepEqual(expected, actual);
153 | });
154 | });
155 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-ec2bf3b4
156 | describe('H=`{}` P=`` ===> T=`$input.keySet`', function() {
157 | it('return ', function() {
158 | var expected = {};
159 | var actual = JSON.parse(mappingTemplate({template: "$input.keySet", payload: ""}));
160 | assert.deepEqual(expected, actual);
161 | });
162 | });
163 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-3e03488f
164 | describe('H=`{}` P=`` ===> T=`$input.params.keySet`', function() {
165 | it('return ', function() {
166 | var expected = {};
167 | var actual = JSON.parse(mappingTemplate({template: "$input.params.keySet", payload: ""}));
168 | assert.deepEqual(expected, actual);
169 | });
170 | });
171 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-a35f2355
172 | describe('H=`{}` P=`` ===> T=`$util`', function() {
173 | it('return ', function() {
174 | var expected = {};
175 | var actual = JSON.parse(mappingTemplate({template: "$util", payload: ""}));
176 | assert.deepEqual(expected, actual);
177 | });
178 | });
179 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-29301967
180 | describe('H=`{}` P=`` ===> T=`$input.params`', function() {
181 | it('return ', function() {
182 | var expected = {};
183 | var actual = JSON.parse(mappingTemplate({template: "$input.params", payload: ""}));
184 | assert.deepEqual(expected, actual);
185 | });
186 | });
187 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-819c3c26
188 | describe('H=`{}` P=`` ===> T=`$input.json`', function() {
189 | it('return ', function() {
190 | var expected = {};
191 | var actual = JSON.parse(mappingTemplate({template: "$input.json", payload: ""}));
192 | assert.deepEqual(expected, actual);
193 | });
194 | });
195 | // https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-caa3f41d
196 | describe('H=`{}` P=`` ===> T=`$util.urlEncode`', function() {
197 | it('return ', function() {
198 | var expected = {};
199 | var actual = JSON.parse(mappingTemplate({template: "$util.urlEncode", payload: ""}));
200 | assert.deepEqual(expected, actual);
201 | });
202 | });
203 | });
--------------------------------------------------------------------------------
/test/_.md:
--------------------------------------------------------------------------------
1 | ## example-12f77fd5
2 | Template|Header|Payload|Status code|Result
3 | --------|------|-------|-----------|------
4 | `"$input.path('$')"`|`None`|`a=b`|`200`|`"a=b"`
5 |
6 | ## example-fcaf7ddd
7 | Template|Header|Payload|Status code|Result
8 | --------|------|-------|-----------|------
9 | `"$input.path('$')"`|`None`|`"a=b"`|`200`|`"a=b"`
10 |
11 | ## example-0dce6fa3
12 | Template|Header|Payload|Status code|Result
13 | --------|------|-------|-----------|------
14 | `$input.json('$')`|`None`|`a=b`|`200`|`"a=b"`
15 |
16 | ## example-dbd6cf1c
17 | Template|Header|Payload|Status code|Result
18 | --------|------|-------|-----------|------
19 | `$input.json('$')`|`None`|`"a=b"`|`200`|`"a=b"`
20 |
21 | ## example-03be1e25
22 | Template|Header|Payload|Status code|Result
23 | --------|------|-------|-----------|------
24 | `"$input.path('$')"`|`None`|`{}`|`200`|`"{}"`
25 |
26 | ## example-1b8d22cd
27 | Template|Header|Payload|Status code|Result
28 | --------|------|-------|-----------|------
29 | `"$input.path('$')"`|`None`|`"{}"`|`200`|`"{}"`
30 |
31 | ## example-b9f18c27
32 | Template|Header|Payload|Status code|Result
33 | --------|------|-------|-----------|------
34 | `$input.json('$')`|`None`|`{}`|`200`|`{}`
35 |
36 | ## example-098fd028
37 | Template|Header|Payload|Status code|Result
38 | --------|------|-------|-----------|------
39 | `$input.json('$')`|`None`|``|`200`|`{}`
40 |
41 | ## example-91575d0e
42 | Template|Header|Payload|Status code|Result
43 | --------|------|-------|-----------|------
44 | `$input.path('$')`|`None`|``|`200`|`{}`
45 |
46 | ## example-25c6993c
47 | Template|Header|Payload|Status code|Result
48 | --------|------|-------|-----------|------
49 | `{"name": "$input.path('$')"}`|`None`|`name=toqoz`|`200`|`{"name":"name=toqoz"}`
50 |
51 | ## example-122ff6ce
52 | Template|Header|Payload|Status code|Result
53 | --------|------|-------|-----------|------
54 | `"$input.path('$')"`|`None`|`{a`|`400`|`{"message": "Could not process payloadnet.minidev.json.parser.ParseException: Unexpected End Of File position 1: null"}`
55 |
56 | ## example-d4719b3d
57 | Template|Header|Payload|Status code|Result
58 | --------|------|-------|-----------|------
59 | `"$input.path('$')"`|`None`|`a{b`|`200`|`"a{b"`
60 |
61 | ## example-2b1f2df4
62 | Template|Header|Payload|Status code|Result
63 | --------|------|-------|-----------|------
64 | `"$input.path('$')"`|`None`|`[a`|`400`|`{"message": "Could not process payloadnet.minidev.json.parser.ParseException: Unexpected End Of File position 1: EOF"}`
65 |
66 | ## example-c0cfe50d
67 | Template|Header|Payload|Status code|Result
68 | --------|------|-------|-----------|------
69 | `"$input.path('$')"`|`None`|`a[`|`200`|`"a["`
70 |
71 | ## example-a7361ae0
72 | Template|Header|Payload|Status code|Result
73 | --------|------|-------|-----------|------
74 | `"$input.path('$')"`|`None`|`null{`|`200`|`"null{"`
75 |
76 | ## example-728fbd1f
77 | Template|Header|Payload|Status code|Result
78 | --------|------|-------|-----------|------
79 | `"$input.path('$')"`|`None`|`true{`|`200`|`"true{"`
80 |
81 | ## example-461fd8fa
82 | Template|Header|Payload|Status code|Result
83 | --------|------|-------|-----------|------
84 | `"$input.path('$')"`|`None`|`false{`|`200`|`"false{"`
85 |
86 | ## example-48665148
87 | Template|Header|Payload|Status code|Result
88 | --------|------|-------|-----------|------
89 | `"$input.path('$')"`|`None`|`undefined{`|`200`|`"undefined{"`
90 |
91 | ## example-cd963d7c
92 | Template|Header|Payload|Status code|Result
93 | --------|------|-------|-----------|------
94 | `$input`|`None`|``|`200`|`{}`
95 |
96 | ## example-ec2bf3b4
97 | Template|Header|Payload|Status code|Result
98 | --------|------|-------|-----------|------
99 | `$input.keySet`|`None`|``|`200`|`{}`
100 |
101 | ## example-3e03488f
102 | Template|Header|Payload|Status code|Result
103 | --------|------|-------|-----------|------
104 | `$input.params.keySet`|`None`|``|`200`|`{}`
105 |
106 | ## example-a35f2355
107 | Template|Header|Payload|Status code|Result
108 | --------|------|-------|-----------|------
109 | `$util`|`None`|``|`200`|`{}`
110 |
111 | ## example-29301967
112 | Template|Header|Payload|Status code|Result
113 | --------|------|-------|-----------|------
114 | `$input.params`|`None`|``|`200`|`{}`
115 |
116 | ## example-819c3c26
117 | Template|Header|Payload|Status code|Result
118 | --------|------|-------|-----------|------
119 | `$input.json`|`None`|``|`200`|`{}`
120 |
121 | ## example-caa3f41d
122 | Template|Header|Payload|Status code|Result
123 | --------|------|-------|-----------|------
124 | `$util.urlEncode`|`None`|``|`200`|`{}`
125 |
126 |
--------------------------------------------------------------------------------
/test/input.js:
--------------------------------------------------------------------------------
1 | var assert = require('assert');
2 | var mappingTemplate = require('../');
3 |
4 | describe('$input', function() {
5 | describe('null object references', function () {
6 | it('render as empty string', function() {
7 | assert.equal(mappingTemplate({template: '$input.path("$").item1', payload: '{"item1":"hello world"}'}), 'hello world');
8 | assert.equal(mappingTemplate({template: '$input.path("$").item2', payload: '{"item1":"hello world"}'}), '');
9 | });
10 | });
11 |
12 | describe('.path(x)', function () {
13 | it('returns object at x(JSON Path) in payload', function() {
14 | assert.equal(mappingTemplate({template: '$input.path("$")', payload: "toqoz"}), 'toqoz');
15 | assert.equal(mappingTemplate({template: '$input.path("$")', payload: "to{qoz"}), 'to{qoz');
16 |
17 | assert.throws(function() { mappingTemplate({template: '$input.path("$")', payload: '{'}); }, Error);
18 | assert.throws(function() { mappingTemplate({template: '$input.path("$")', payload: '['}); }, Error);
19 |
20 | assert.equal(mappingTemplate({template: '$input.path("$.name")', payload: '{"name": "toqoz"}'}), 'toqoz');
21 | assert.equal(mappingTemplate({template: '$input.path("$.names")', payload: '{"names": ["toqoz", "foo", "bar"]}'}), '[toqoz, foo, bar]');
22 | });
23 | });
24 |
25 | describe('.json(x)', function () {
26 | it('returns object at x(JSON Path) in payload', function() {
27 | assert.equal(mappingTemplate({template: '$input.json("$.name")', payload: '{"name": "toqoz"}'}), '"toqoz"');
28 | assert.equal(mappingTemplate({template: '$input.json("$.names")', payload: '{"names": ["toqoz", "foo", "bar"]}'}), '["toqoz","foo","bar"]');
29 | });
30 | });
31 |
32 | describe('.params(x)', function () {
33 | var template = '$input.params("name")';
34 |
35 | it('searchs the value from path at first', function() {
36 | assert.equal(mappingTemplate({template: template, payload: "", params: {path: {name: "toqoz"}, querystring: {name: "ftoqoz"}, header: {name: "fftoqoz"}}}), 'toqoz');
37 | });
38 |
39 | it('searchs the value from querystring at second', function() {
40 | assert.equal(mappingTemplate({template: template, payload: "", params: {querystring: {name: "toqoz"}, header: {name: "ftoqoz"}}}), 'toqoz');
41 | });
42 |
43 | it('searchs the value from header at third', function() {
44 | assert.equal(mappingTemplate({template: template, payload: "", params: {header: {name: "toqoz"}}}), 'toqoz');
45 | });
46 | });
47 |
48 | describe('.params()', function () {
49 | describe('.header', function() {
50 | it('is header', function() {
51 | var template = '{"header": "$input.params().header"}';
52 | var result = mappingTemplate({template: template, payload: "", params: {header: {"NAME": "TOQOZ", "AGE": 999}}});
53 | assert.equal(result, '{"header": "{NAME=TOQOZ, AGE=999}"}');
54 | });
55 |
56 | describe('.get(x)', function() {
57 | it('returns header value for x', function () {
58 | var template = "{\"name\": \"$input.params().header.get('NAME')\"}";
59 | var result = mappingTemplate({template: template, payload: "", params: {header: {"NAME": "TOQOZ", "AGE": 999}}});
60 | assert.equal(result, '{"name": "TOQOZ"}');
61 | });
62 | });
63 |
64 | describe('.entrySet()', function() {
65 | it('returns entry(=key-value) set', function () {
66 | var template = "\"$input.params().header.entrySet()\"";
67 | var result = mappingTemplate({template: template, payload: "", params: {header: {"NAME": "TOQOZ", "AGE": 999}}});
68 | assert.equal(result, '"[{key=NAME, value=TOQOZ}, {key=AGE, value=999}]"');
69 | });
70 | describe('.size()', function() {
71 | it('returns length of receiver', function () {
72 | var template = "$input.params().header.entrySet().size()";
73 | var result = mappingTemplate({template: template, payload: "", params: {header: {"NAME": "TOQOZ", "AGE": 999}}});
74 | assert.equal(result, "2");
75 | });
76 | });
77 | });
78 |
79 | describe('.keySet()', function() {
80 | it('returns key set', function () {
81 | var template = "\"$input.params().header.keySet()\"";
82 | var result = mappingTemplate({template: template, payload: "", params: {path: {id: 12}, querystring: {}, header: {"NAME": "TOQOZ", "AGE": 999}}});
83 | assert.equal(result, '"[NAME, AGE]"');
84 | });
85 |
86 | describe('.size()', function() {
87 | it ('returns length of receiver', function() {
88 | var template = "$input.params().header.keySet().size()";
89 | var result = mappingTemplate({template: template, payload: "", params: {path: {id: 12}, querystring: {}, header: {"NAME": "TOQOZ", "AGE": 999}}});
90 | assert.equal(result, "2");
91 | });
92 | });
93 | });
94 |
95 | describe('.keySet() and .get(x)', function() {
96 | it('returns header names', function () {
97 | var template =
98 | '{' +
99 | '#foreach($key in $input.params().header.keySet())' +
100 | '"$key": "$input.params().header.get($key)"#if($foreach.hasNext), #end' +
101 | '#end' +
102 | '}';
103 | var header = {"NAME": "TOQOZ", "AGE": 999};
104 | var result = mappingTemplate({template: template, payload: "", params: {header: header}});
105 | assert.equal(result, '{"NAME": "TOQOZ", "AGE": "999"}');
106 | });
107 | });
108 | });
109 | });
110 | });
111 |
--------------------------------------------------------------------------------
/test/renderer.js:
--------------------------------------------------------------------------------
1 | var assert = require('assert');
2 | var mappingTemplate = require('../');
3 |
4 | describe("escape HTML", function() {
5 | it("DO NOT", function() {
6 | assert.equal(mappingTemplate({template: '$input.path("$")', payload: ""}), '');
7 | assert.equal(mappingTemplate({template: '$input.path("$")', payload: ""}), '');
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/test/util.js:
--------------------------------------------------------------------------------
1 | var assert = require('assert');
2 | var mappingTemplate = require('../');
3 |
4 | describe('$util', function() {
5 | describe('.escapeJavaScript()', function() {
6 | it ('escapes as javascript string', function() {
7 | var template = '$util.escapeJavaScript($input.path(\'$\'))';
8 | var result = mappingTemplate({template: template, payload: 'bo"dy'});
9 | assert.equal(result, 'bo\"dy');
10 | });
11 | });
12 | describe('.urlEncode()', function() {
13 | it ('encodes to url', function() {
14 | var template = '$util.urlEncode($input.path(\'$\'))';
15 | var actual = mappingTemplate({template: template, payload: 'エーピーアイゲートウェイ テンプレートマッピング'});
16 | var expected = '%E3%82%A8%E3%83%BC%E3%83%94%E3%83%BC%E3%82%A2%E3%82%A4%E3%82%B2%E3%83%BC%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A4%20%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%83%9E%E3%83%83%E3%83%94%E3%83%B3%E3%82%B0';
17 | assert.equal(actual, expected);
18 | });
19 | });
20 | describe('.urlDecode()', function() {
21 | it ('decodes from url', function() {
22 | var template = '$util.urlDecode($input.path(\'$\'))';
23 | var actual = mappingTemplate({template: template, payload: '%E3%82%A8%E3%83%BC%E3%83%94%E3%83%BC%E3%82%A2%E3%82%A4%E3%82%B2%E3%83%BC%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A4%20%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%83%9E%E3%83%83%E3%83%94%E3%83%B3%E3%82%B0'});
24 | var expected = 'エーピーアイゲートウェイ テンプレートマッピング';
25 | assert.equal(actual, expected);
26 | });
27 | });
28 | describe('.base64Encode()', function() {
29 | it ('encodes to base64', function() {
30 | var template = '$util.base64Encode($input.path(\'$\'))';
31 | var actual = mappingTemplate({template: template, payload: 'エーピーアイゲートウェイテンプレートマッピング'});
32 | var expected = '44Ko44O844OU44O844Ki44Kk44Ky44O844OI44Km44Kn44Kk44OG44Oz44OX44Os44O844OI44Oe44OD44OU44Oz44Kw';
33 | assert.equal(actual, expected);
34 | });
35 | });
36 | describe('.base64Decode()', function() {
37 | it ('decode from base64', function() {
38 | var template = '$util.base64Decode($input.path(\'$\'))';
39 | var actual = mappingTemplate({template: template, payload: '44Ko44O844OU44O844Ki44Kk44Ky44O844OI44Km44Kn44Kk44OG44Oz44OX44Os44O844OI44Oe44OD44OU44Oz44Kw'});
40 | var expected = 'エーピーアイゲートウェイテンプレートマッピング';
41 | assert.equal(actual, expected);
42 | });
43 | });
44 | });
45 |
--------------------------------------------------------------------------------