カフェでMacを開きたい

仕事とか技術とか趣味とか

AWS API Gatewayでapplication/x-www-form-urlencodedの配列パラメータを扱いたい時のマッピングテンプレート

hoge[]を受け取りたい

AWS LambdaとAPI Gatewayを連携させてPOSTを受け取って・・・とやろうとした時に、配列のパラメータの扱いで少しハマりました。

application/x-www-form-urlencodedの単純なkey=valueのPOSTを扱うマッピングテンプレートは、ググればたくさん出てくるんですが、key[]=valueの配列を扱えるものはほとんど出てきませんでした。

唯一まとめてくださっていたのが以下の記事。

takigawa401.hatenablog.com

こちらの記事のテンプレートをコピペしても動くんですが、リクエスト時のパラメータの状態によって整形後のjsonが不正な形式(浮いたカンマがある)になる場合があったので、自分なりにちょっと改造をしてみました。

テンプレート

{
    "headers" : {
        #foreach( $key in $input.params().header.keySet() )
            "$key" : "$input.params().header.get($key)"#if( $foreach.hasNext ),#end
        #end
    },
    "queryParameters" : {
        #set( $tmpStr = $input.path('$') )

        ##配列をまとめるハッシュと単純な値をまとめるハッシュ
        #set( $arrayKeyValue = {} )
        #set( $simpleKeyValue = {} )

        #foreach( $keyAndValueStr in $tmpStr.split( '&' ) )
            #set( $keyAndValueArray = $keyAndValueStr.split( '=' ) )

            #if( $keyAndValueArray[0].indexOf('[]') > 0)
                ##「key[]=value」を「key : [value]」に変換してまとめる
                #set($arraykey = $keyAndValueArray[0].substring(0, $keyAndValueArray[0].indexOf('[]') ))
                #set($arrayvalue = [])
                
                #if($arrayKeyValue.containsKey($arraykey))
                  #set($arrayvalue = $arrayKeyValue.get($arraykey))
                #end
                
                #set($dev_null = $arrayvalue.add($keyAndValueArray[1]))
                #set($dev_null = $arrayKeyValue.put($arraykey, $arrayvalue) )
                
            #elseif( $keyAndValueArray[0].indexOf('%5B%5D') > 0)
                ##「key[]=value」を「key : [value]」に変換してまとめる(上と全く同じことをやっている)
                #set($arraykey = $keyAndValueArray[0].substring(0, $keyAndValueArray[0].indexOf('%5B%5D') ))
                #set($arrayvalue = [])
                
                #if($arrayKeyValue.containsKey($arraykey))
                  #set($arrayvalue = $arrayKeyValue.get($arraykey))
                #end
                
                #set($dev_null = $arrayvalue.add($keyAndValueArray[1]))
                #set($dev_null = $arrayKeyValue.put($arraykey, $arrayvalue) )
                
            #else
                ##単純な「key : value」でまとめる
                #set($dev_null = $simpleKeyValue.put($keyAndValueArray[0], $keyAndValueArray[1]) )
            #end
        #end
        
        ##「key : value」を書き起こす
        #foreach( $key in $simpleKeyValue.keySet())
            "$key" : "$util.urlDecode($simpleKeyValue.get($key))"#if($foreach.hasNext() || $arrayKeyValue.size() > 0),#end
        #end
        
        ##「key : [value]」を書き起こす
        #foreach( $key in $arrayKeyValue.keySet())
            #set( $resultValArr = $arrayKeyValue.get($key) )
            "$key" : [#foreach($val in $resultValArr)"$util.urlDecode($val)"#if($foreach.hasNext()),#end#end]#if($foreach.hasNext()),#end
        #end
    },
    "stage" : "$context.stage",
    "sourceIp" : "$context.identity.sourceIp",
    "userAgent" : "$context.identity.userAgent"
}

解説とまとめ

単純なkey=valueをまとめるハッシュと、配列のkey[]=valueをまとめるハッシュを別にしました。

最初にパラメータを分解してハッシュに一通りまとめて、最後にいっぺんに文字列として書き起こしていく流れです。

参照元の記事では、配列をハッシュにまとめている間に単純なkey=valueは文字に起こしていたのですが、個人的に「分解→整形」の流れにした方が分かりやすかったので、別々の変数にまとめました。

これでどんなパラメータがきても対応できると思います。

一つ注意といえば、数値も全部文字列にしてしまうので、受け取る側で適宜型変換をしないと行けない点ですね。

application/x-www-form-urlencodedだと結構面倒ごとが多いから大人しくapplication/jsonで送ってもらうのが良いのかもしれません・・・。