web-dev-qa-db-fra.com

Comment passer un params de POST à AWS Lambda à partir de Amazon API Gateway

Dans cette question Comment passer un paramètre de chaîne de requête ou de route à AWS Lambda à partir de Amazon API Gateway

montre comment mapper les paramètres de chaîne de requête sur AWS lambda à l'aide de la passerelle API. Je voudrais faire la même chose, mais en mappant les valeurs POST au lieu de query-string. J'ai essayé:

{
    "values": "$input.params()"
}

mais n'a pas fonctionné, je ne vois pas les données de formulaire réelles. BTW je poste en utilisant: 

application/x-www-form-urlencoded

Je reçois ma réponse de ma fonction lambda. Je sais donc qu'elle appelle lambda fin, mais mon problème est que je ne vois nulle part les paramètres POST. Je n'arrive pas à comprendre comment les cartographier. Je vide tout ce que je reçois du côté Lambda et le voici:

 {"values":"{path={}, querystring={}, header={Accept=*/*, Accept-Encoding=gzip, deflate, Accept-Language=en-US,en;q=0.8, Cache-Control=no-cache, CloudFront-Forwarded-Proto=https, CloudFront-Is-Desktop-Viewer=true, CloudFront-Is-Mobile-Viewer=false, CloudFront-Is-SmartTV-Viewer=false, CloudFront-Is-Tablet-Viewer=false, CloudFront-Viewer-Country=US, Content-Type=application/x-www-form-urlencoded, Origin=chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop, Postman-Token=7ba28698-8753-fcb1-1f48-66750ce12ade, Via=1.1 6ba5553fa41dafcdc0e74d152f3a7a75.cloudfront.net (CloudFront), X-Amz-Cf-Id=sc8C7dLcW0BHYopztNYrnddC0hXyFdBzHv0O9aWU1gKhd1D_J2HF3w==, X-Forwarded-For=50.196.93.57, 54.239.140.62, X-Forwarded-Port=443, X-Forwarded-Proto=https}}"}
34
ecorvo

Bonne réponse de r7kamura. De plus, voici un exemple de modèle de mappage compréhensible et robuste pour application/x-www-form-urlencoded qui fonctionne dans tous les cas (en supposant que POST):

{
    "data": {
        #foreach( $token in $input.path('$').split('&') )
            #set( $keyVal = $token.split('=') )
            #set( $keyValSize = $keyVal.size() )
            #if( $keyValSize >= 1 )
                #set( $key = $util.urlDecode($keyVal[0]) )
                #if( $keyValSize >= 2 )
                    #set( $val = $util.urlDecode($keyVal[1]) )
                #else
                    #set( $val = '' )
                #end
                "$key": "$val"#if($foreach.hasNext),#end
            #end
        #end
    }
}

Cela transformerait une entrée de

name=Marcus&email=email%40example.com&message=

dans

{
    "data": {
                "name": "Marcus",
                "email": "[email protected]",
                "message": ""
    }
}

Un gestionnaire Lambda pourrait l'utiliser comme ceci (celui-ci renvoie toutes les données d'entrée):

module.exports.handler = function(event, context, cb) {
  return cb(null, {
    data: event.data
  });
};
54
Marcus Whybrow

Vous pouvez convertir toutes les données du corps de la demande au format JSON valide en configurant les modèles de mappage dans les paramètres d'intégration afin que AWS Lambda puisse les recevoir.

Actuellement, il semble que Amazon API Gateway ne supporte pas encore officiellement application/x-www-form-urlencoded, mais avilewin a posté une solution pour le faire sur les forums AWS. Dans les modèles de mappage, vous pouvez utiliser VTL (Velocity Template Language) , vous devez donc configurer des modèles de mappage qui convertissent le format application/x-www-form-urlencoded en un format JSON valide. Bien sûr, c’est une solution sale, mais je pense que c’est la seule façon de le faire pour le moment.

20
r7kamura

Si vous activez l’intégration Lambda Proxy  enter image description here

Le corps POST sera disponible à partir de:

event['body']['param']

Les paramètres et les en-têtes GET seront également disponibles via

event['pathParameters']['param1']
event["queryStringParameters"]['queryparam1']
event['requestContext']['identity']['userAgent']
event['requestContext']['identity']['sourceIP']
12
Jonathan

Vous pouvez convertir les paramètres en JSON avec un modèle de passerelle d’API: https://forums.aws.Amazon.com/thread.jspa?messageID=673012&tstart=0#673012

Ou vous pouvez le faire dans la fonction lambda elle-même en utilisant l’analyseur QueryString: https://www.npmjs.com/package/qs

var qs = require('qs');
var obj = qs.parse('a=c');  // { a: 'c' } 

Si Amazon ajoute une prise en charge intégrée pour une telle fonctionnalité, je l'utiliserai, mais jusque-là, je préfère personnellement la deuxième méthode, car elle est plus propre et plus facile à déboguer en cas de problème.

Mise à jour juillet 2017:

Vous pouvez utiliser une intégration proxy qui la prend en charge par défaut: http://docs.aws.Amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for- lambda.html

11
advncd

Extension de la réponse @ markus-whybrow:

{
        #foreach( $token in $input.path('$').split('&') )
            #set( $keyVal = $token.split('=') )
            #set( $keyValSize = $keyVal.size() )
            #if( $keyValSize >= 1 )
                #set( $key = $util.urlDecode($keyVal[0]) )
                #if( $keyValSize >= 2 )
                    #set( $val = $util.urlDecode($keyVal[1]) )
                #else
                    #set( $val = '' )
                #end
                "$key": "$util.escapeJavaScript($val)"#if($foreach.hasNext),#end
            #end
        #end
    }

Cela supprime les "données" et corrige également le cas si vous avez une double citation dans l'une de vos valeurs.

3
Mark Sergienko

J'ai implémenté une API avec POST demandes où Content-Type était application/x-www-form-urlencoded. Si vous souhaitez simplement obtenir une longue chaîne de requête de valeurs similaires aux demandes GET, utilisez cette syntaxe de mappage.

{
    "body": "$input.body"
}

Remarque, vous pouvez aussi ajouter d'autres mappages ... J'ai laissé cela de côté pour résoudre le problème initial.

Voici un didacticiel de blog que j'ai utilisé lors de la mise en œuvre initiale de mon API. Ma fonction lambda analyse ensuite la chaîne de requête et transmet les données à d’autres processus. 

2
openwonk

J'ai trouvé une solution très simple qui mérite d'être partagée, car il m'a fallu un certain temps pour trouver ce code fonctionnel minimal.

Si vous avez un formulaire commun, qui envoie des données avec le type de contenu application/x-www-form-urlencoded, indiquez simplement "Intégration de proxy lambda". Vous trouverez ensuite des données de formulaire codées dans event.body qui peuvent être analysées avec Node.js. module natif de chaîne de requête.

const querystring = require('querystring')

function handler (event, context, callback) {
  // Read form data.
  const { user, pass } = querystring.parse(event.body)

  // Follows your code to handle request.
}
1
Gianluca Casati

Fonction simple qui renvoie le dictionnaire ordonné des valeurs postées:

import urllib
from collections import OrderedDict
postdata = ''

def GetPostData(body):
    #postdata = OrderedDict()
    postdata = {}
    for items in body.split('&'):
        vals = items.split('=')
        postdata[vals[0]] = urllib.parse.unquote(vals[1])
    return postdata

#Testing it out:
#Assume you get body from event['body'] or body = event.get['body']
body = 'text=This%20works%20really%20well%21%245123%21%403%2146t5%40%2341&anotherkey=isawesome23412%201%21%403%21%40312'

postdata = GetPostData(body)
print(postdata['text'])
#returns 'This works really well!$5123!@3!46t5@#41'
print(postdata['anotherkey'])
#returns 'isawesome23412 1!@3!@312'

Pour éviter une erreur de clé lorsqu'un élément publié est manquant, vous devez plutôt utiliser value = postdata.get (''), car la valeur sera None si la clé n'est pas présente.

0
Arvin Amir

Ceci fonctionne avec l'intégration lambda . En supposant que le corps de votre demande POST soit par exemple. 

{
   "name" : "Hello",
   "address" : "Cool place" 
}

Vous pouvez y accéder comme suit: 

if (event.body !== null && event.body !== undefined) {
   let body = JSON.parse(event.body)
   let name = body.name;
   let address = body.address;
}

Plus d'infos ici: http://docs.aws.Amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html

0
Dodi