English / 日本語
Makes Amazon API Gateway's mapping template composable.
This library is especially powerful if you combine it with AWS Cloud Development Kit.
npm install https://github.com/codemonger-io/mapping-template-compose.git#v0.1.1
Have you ever felt that describing mapping templates for Amazon API Gateway is cumbersome? I got tired of writing mapping templates because:
-
I had to write a lot of boilderplate code; e.g., extracting a query parameter as a property:
"username": "$util.escapeJavaScript($util.urlDecode($input.params("username"))).replaceAll("\\'", "'")"
-
It was difficult to reuse components of mapping templates
Regarding the second issue, the major difficulty is in making sure a JSON representation resulting from a mapping template valid.
Suppose you have the following property definitions as components:
const username = `"username": "$util.escapeJavaScript($util.urlDecode($input.params("username"))).replaceAll("\\'", "'")"`;
const signature = `"signature": $input.json("$.signature")`;
const date = `"date": "$util.escapeJavaScript($util.urlDecode($input.params("date"))).replaceAll("\\'", "'")"`;
If we want to construct a simple object that has all the above properties:
{
"username": "$util.escapeJavaScript($util.urlDecode($input.params("username"))).replaceAll("\\'", "'")",
"signature": $input.json("$.signature"),
"date": "$util.escapeJavaScript($util.urlDecode($input.params("date"))).replaceAll("\\'", "'")"
}
You have to omit a trailing comma after the last property date
, though, this is rather straightforward:
`{
${[username, signature, date].join(',\n ')}
}`
What if all the properties may be omitted? You might come up with the following code:
`{
#if ($input.params('username') != "")
${username},
#end
#if ($input.json('$.signature') != "")
${signature},
#end
#if ($input.params('date') != "")
${date}
#end
}`
Unfortunately, the above template does not always produce a valid JSON object.
It will end up with a dangling comma if date
is omitted.
{
"username": "<username>",
"signature": "<signature>",
}
We have do something like below:
`{
#if ($input.params('username') != "")
${username}
#end
#if ($input.json('$.signature') != "")
#if ($input.params('username') != "")
,
#end
${signature}
#end
#if ($input.params('date') != "")
#if (($input.params('username') != "") || ($input.json('$.signature') != ""))
,
#end
${date}
#end
}`
It is daunting, isn't it? This library is intended to relieve the pain of writing mapping templates like the above.
You can rewrite the example in the previous section with this library into:
import { composeMappingTemplate, ifThen } from 'mapping-template-compose';
composeMappingTemplate([
ifThen(
'$input.params("username") != ""',
[['username', `"$util.escapeJavaScript($util.urlDecode($input.params("username"))).replaceAll("\\'", "'")"`]],
),
ifThen(
'$input.json("signature") != ""',
[['signature', '$input.json("$.signature")']],
),
ifThen(
'$input.params("date") != ""',
[['date', `"$util.escapeJavaScript($util.urlDecode($input.params("date"))).replaceAll("\\'", "'")"`]],
),
]);
You can make it further modular:
import { type KeyValue, composeMappingTemplate, ifThen } from 'mapping-template-compose';
const username: KeyValue = ['username', `"$util.escapeJavaScript($util.urlDecode($input.params("username"))).replaceAll("\\'", "'")"`];
const signature: KeyValue = ['signature', '$input.json("$.signature")'];
const date: KeyValue = ['date', `"$util.escapeJavaScript($util.urlDecode($input.params("date"))).replaceAll("\\'", "'")"`];
const optionalUsername = ifThen('$input.params("username") != ""', [username]);
const optionalSignature = ifThen('$input.json("signature") != ""', [signature]);
const optionalDate = ifThen('$input.params("date") != ""', [date]);
composeMappingTemplate([
optionalUsername,
optionalSignature,
optionalDate,
]);
What this library specifically does is only one thing: to determine where to place a comma (",").
However, this seemingly trivial task turns out complicated as you can see in the example in Section "Motivation".
Thus, not all of the possible patterns in mapping templates are supported.
For instance, looping is not supported yet.
Please refer to supported-patterns.md
for what mapping template you can compose with this library.
You can find the API documentation in ./api-docs/markdown
folder.
npm ci
npm run build
npm test
npm run build:doc