【问题标题】:How to set object key-values in AWS API Gateway Mapping Template如何在 AWS API Gateway 映射模板中设置对象键值
【发布时间】:2018-06-28 14:37:13
【问题描述】:

我最近熟悉了 AWS 最奇特的 API 网关映射模板语法,这对我来说并没有多大意义。

我试图阅读文档,但至少说 https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html#util-template-reference 有点令人费解

我想做的很简单。我有一个 JSON 格式的请求正文,我想在其中添加附加字段 timeReceived,并将 $context.requestTime 作为其值。我天真的第一次尝试是#set( $bodyObj.timeReceived = $context.requestTime ),但没有成功。

我很肯定我会让它发挥作用,但做这样简单的事情需要时间和精力,IMO 很愚蠢,AWS 应该改进现有的文档。

编辑:我在下面编写的解决方案有效,但我主张重新考虑使用 API Gateway。我最近更新了我的应用程序以使用 edge lambda 和 CloudFront,这在各个方面都是一个更好的解决方案。 lambda 的一些棘手配置无法使用环境变量,因此将 DeliveryStreamName 自动化到代码中有点问题(我最终使用带有 Sceptre 的自定义解析器)。但还是好多了。并且不需要这些愚蠢的 hack =)。

【问题讨论】:

    标签: amazon-web-services aws-api-gateway


    【解决方案1】:

    编辑:在写这篇文章时,我发现 1# 我没有部署我的更改,很尴尬,而且 2# 它有效。现在我只需要使用添加的字段将 JSON 字符串化。

    10 分钟后: 嗯,这很难……所以我发现这个可行:

    #set($payload = $util.parseJson($input.json('$')))
    #set($body =  "{
      #foreach ($mapEntry in $payload.entrySet())
        ""$mapEntry.key"": ""$mapEntry.value"",
      #end
      ""timeReceived"": ""$context.requestTime"",
      ""x-client-ip"": ""$context.identity.sourceIp""
    }")
    

    但是将 JSON 扩展为多行(JSON 被发送到 Firehose,然后将其存储到 S3)这是不好的。

    20 分钟后:当我告诉我的高级开发人员我在做什么并用几个脏话评论 API 网关映射模板时,他嘲笑我。

    40 分钟后:我知道我必须做什么:用空字符串替换所有换行符,但事实证明这比我想象的要难。我还发现对象内的嵌套值没有被字符串化。

    50 分钟后: 实际上我可以通过将整个 foreach 循环放在单行中来省略换行符替换。但是我再次必须以某种方式对嵌套值进行字符串化。 requestTime 被格式化为一些愚蠢的英文格式(无意冒犯!:))

    70 分钟后:正确设置嵌套值的格式真的很困难。我发现了另一个有效的例子:

    #set($body =  "{
      #foreach ($mapEntry in $payload.entrySet())
        #if ($mapEntry.value.size() > 0)
          ""$mapEntry.key"": {
          #foreach($subEntry in $mapEntry.value.entrySet())
            ""$subEntry.key"": ""$subEntry.value""#if($foreach.hasNext),#end
          #end
          },
        #else
          ""$mapEntry.key"": ""$mapEntry.value"",
        #end
      #end
      ""timeReceived"": $context.requestTimeEpoch}
    }")
    

    如果您不希望在其中添加新行或额外空格,这意味着:

    #set($body = "{#foreach ($mapEntry in $payload.entrySet())#if($mapEntry.value.size() > 0)""$mapEntry.key"": { #foreach($subEntry in $mapEntry.value.entrySet())""$subEntry.key"": ""$subEntry.value""#if($foreach.hasNext), #end#end }, #else""$mapEntry.key"": ""$mapEntry.value"", #end#end""timeReceived"": $context.requestTimeEpoch }" )
    

    花了 120 分钟调试和编写这篇文章:那是一段旅程。我想我已经回答了我自己的问题,所以希望现在有人可以避免像我一样花这么多时间调试这个问题。

    130 分钟后: Aaand 现在我必须解决将字符串添加到我的 CloudFormation 模板中的悲剧。好家伙。 (这甚至不难,困难的部分是重新部署 API 网关,在撰写本文时,我必须从控制台手动完成)

    【讨论】:

    • “最奇特的语法”是VTL。在每行末尾添加##(注释)应该具有吞下每行末尾的换行符的副作用,允许人类可读的模板仍然产生没有换行符的输出。
    • 映射模板也适用于嵌套的 JSON!但是,JSON 中的数字值将被双引号括起来。有什么方法可以忽略数字值的双引号?
    • 我通过将新字段连接到 JSON 字符串解决了这个问题
    • 如果您有一个 json 对象数组作为子值,则不起作用。
    猜你喜欢
    • 2020-09-28
    • 2017-11-30
    • 2017-12-29
    • 1970-01-01
    • 1970-01-01
    • 2018-12-04
    • 2018-02-03
    • 2018-01-20
    • 2016-01-21
    相关资源
    最近更新 更多