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.2.0
Every time commits are pushed to the main
branch, a developer package is published to the npm registry managed by GitHub Packages.
A developer package bears the next release version number but followed by a dash (-
) plus the short commit hash; e.g., 0.2.0-abc1234
where abc1234
is the short commit hash of the commit used to build the package (snapshot).
You can find developer packages here.
To install a developer package, you need to configure a classic GitHub personal access token (PAT) with at least the read:packages
scope.
Below briefly explains how to configure a PAT.
Please refer to the GitHub documentation for more details.
Once you have a PAT, please create a .npmrc
file in your home directory with the following content:
//npm.pkg.github.com/:_authToken=$YOUR_GITHUB_PAT
Please replace $YOUR_GITHUB_PAT
with your PAT.
In the root directory of your project, please create a .npmrc
file with the following content:
@codemonger-io:registry=https://npm.pkg.github.com
Then you can install a developer package with the following command:
npm install @codemonger-io/mapping-template-compose@0.2.0-abc1234
Please replace abc1234
with the short commit hash of the snapshot you want to install.
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 '@codemonger-io/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 '@codemonger-io/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.
pnpm install --frozen-lockfile
pnpm build
pnpm test
pnpm build:doc