I understand that API Gateway (AG) passes params into Lambda as JSON payload.
I have setup a POST API with Lambda Proxy in AG. My lambda function takes the following param list :
{
"fullname": "Mr xxxxx",
"clientemail": "xxxxxx#xxx.com",
"clientphone": "0800 088 8888",
"locationtext": "Laxxxxxx Hotel , CA, USA",
"subject": "Gxxxxxrth",
"appointmentblock_min": "60",
"buffer": "120",
"calendar_id": "xxxxx",
"thedate": "2021-03-2xxxxxx",
"thetime": "xxxxx"
}
Testing directly within the Lambda console. Everything works fine. I map all parameters in the code using the lambda EVENT object as follows :
fullname = event['fullname']
clientemail = event['clientemail']
appointmentblock_min = int(event['appointmentblock_min'])
... and so on.
All code works fine.
Adding the API Gateway component on top ... and things don't work.
The specific problem : how can I map the lambda input parameters coming from API Gateway (AG) to lambda ?
I realise that AG is sending JSON into Lambda. How to parse this payload to extract and use the parameters that I need.
I have tried to create a dict containing all the parameters :
Event = {}
Event = json.loads(body)
Event = json.loads(event.body)
No docs explicitly explain how to grab the event object params via AG.
Any help would be appreciated.
PS I am expecting to return data back to AG as follows :
return {
'statusCode': 200,
'headers': {'Content-Type': 'application/json'},
'body': json.dumps(out_message),
'isBase64Encoded': 'false'
}
Thank you for your consideration.
According to TestEvents in Lambda, the input you get on Lambda will be
LambdaTest
So you can load your payload (or body) as
Event = json.loads(event['body'])
Related
I'm working with a AWS API Gateway that receives a {name} as prints out "Hello {name}" but I'm unable to get this trivial task right.
Any pointers what I could be doing wrong? How the can I get the {name} from the URL?
API Gateway:
https://xxxxxx.execute-api.eu-west-1.amazonaws.com/dev/John
Python AWS Lamba code:
def lambda_handler(event, context):
name = event["requestContext"]["resourcePath"]
response = "Hello " + name
return {
'statusCode': 200,
'body': response
}
The expected output:
{
"statusCode": 200,
"body": "Hello John"
}
Use a proper mapping template on Gateway side. It cannot map whatever you want automatically, you need to configure what you expect there.
I'm using the Aws Lambda authorizer to secure an Api gateway. The authorizer lambda function is written in python using this blueprint from aws (https://github.com/awslabs/aws-apigateway-lambda-authorizer-blueprints/blob/master/blueprints/python/api-gateway-authorizer-python.py)
I added this code in the "blueprint"
if(event['authorizationToken'] == 'allow'):
policy.allowAllMethods()
else:
policy.denyAllMethods()
# Finally, build the policy
authResponse = policy.build()
# new! -- add additional key-value pairs associated with the authenticated principal
# these are made available by APIGW like so: $context.authorizer.<key>
# additional context is cached
context = {
'key': 'somevalue, # $context.authorizer.key -> value
'number' : 1,
'bool' : True
}
# context['arr'] = ['foo'] <- this is invalid, APIGW will not accept it
# context['obj'] = {'foo':'bar'} <- also invalid
authResponse['context'] = context
return authResponse
However in the lambda function attached to the route i cannot find the context value from authorizer. How can i get the values from context[key] ?
The solution is to use Mapping Templates on Integration Request. If you look at the route pipeline you will see that before reaching the Lambda Function you have a "Integration Request" section (and also a Integration Response)
In Integration Request you have the option to edit the input into lambda function via Mapping Templates.
So, i created a new Mapping Template ( use "Where" there are no Templates defined)
Content -Type use application/json
and in the actual template use something like
#set($inputRoot = $input.path('$'))
{
"key":"$context.authorizer.key"
}
Attention : the above template will remove the original output. That data is found in $inputRoot and you can add it to response using this format
{
"key":"$context.authorizer.key",
"originalkey":$inputRoot.originalkey
}
With the help of accepted answer I had came up with this:
## See http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html
## This template will pass through all parameters including path, querystring, header, stage variables, and context through to the integration endpoint via the body/payload
#set($inputRoot = $input.path('$'))
#set($authorizer = $context.authorizer)
#set($allParams = $input.params())
{
#foreach($key in $inputRoot.keySet())
"$key" : "$util.escapeJavaScript($inputRoot.get($key))"
#if($foreach.hasNext),#end
#end,
"context" : {
"params" : {
#foreach($type in $allParams.keySet())
#set($params = $allParams.get($type))
"$type" : {
#foreach($paramName in $params.keySet())
"$paramName" : "$util.escapeJavaScript($params.get($paramName))"
#if($foreach.hasNext),#end
#end
}
#if($foreach.hasNext),#end
#end
},
"stage-variables" : {
#foreach($key in $stageVariables.keySet())
"$key" : "$util.escapeJavaScript($stageVariables.get($key))"
#if($foreach.hasNext),#end
#end
},
#foreach($key in $context.keySet())
"$key" : "$util.escapeJavaScript($context.get($key))"
#if($foreach.hasNext),#end
#end,
"authorizer": {
#foreach($key in $authorizer.keySet())
"$key" : "$util.escapeJavaScript($authorizer.get($key))"
#if($foreach.hasNext),#end
#end
}
}
}
edit:
after tweaking around in api gateway I'we found out about
Use Lambda Proxy integration toggle button that adds extra parameters to event object
Writing my first Lambda funcation to put item with Python
The problem im having - not getting the input from the registration form ( front end hosted on S3 bucket with static webhost enabled ) to the DynamoDB table
the Data will be sent with this funcation to the API hosted on AWS
const BASE_URL = `API-URL`;
function handleForm() {
const name = document.querySelector('#name').value;
const email = document.querySelector('#email').value;
const phone = document.querySelector('#phone').value;
const data = {
name,
email,
phone
}
console.log(data);
saveDataToAWS(data);
}
async function saveDataToAWS(data) {
const result = await axios.post(BASE_URL, data);
return result.data;
}
Im not sure im using AXIOS the right way but lets continue
The Lambda funcation im using now is pretty much this :
import json
import boto3
dynamodb=boto3.resource('dynamodb')
table=dynamodb.Table('register')
def lambda_handler(event, context):
table.put_item(
Item={
'name'=event['name'],
'email'=event['email'],
'phone'=event['phone']
}
)
respone={
'mes':'Good input !'
}
return {
'statusCode': 200,
'body': respone
}
Im pretty much 99% new to writting code in AWS so im sure im doing most of it wrong
Really looking for you help !
The 'event' attribute has a 'body' parameter that will contain the data in your example:
data = json.loads(event["body"])
table.put_item(
Item={
'name':data['name'],
'email':data['email'],
'phone':data['phone']
}
)
Remember to check CloudWatch Logs as well, as it will tell you whether the Lambda was invoked in the first place, and if it failed.
More information on the structure of the event-attribute can be found here:
https://aws-lambda-for-python-developers.readthedocs.io/en/latest/02_event_and_context/
Is there a way to set up a rest api using a python lambda function with a get method that uses query parameters by using the amplify CLI or editing the code?
I know this can be done through the AWS Management Console, but was hoping for a more code-oriented solution. Below is the sample lambda I'm trying to use and a simple example of how I would like to get different api responses (length of dummy text string) based on the get method called by the api using something like "curl https://......../myapi?length=4"
import json
def handler(event, context):
print('received event:')
str_len = event['queryStringParameters']['length']
body = {
"message" : "DUMMY TEST"[1:str_len]
}
response = {
"statusCode" : 200,
"body" : json.dumps(body),
"headers" : {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
}
}
return response
When I look at the documentation for passing parameters to the Jasper Report REST 2 API here: http://community.jaspersoft.com/documentation/jasperreports-server-web-services-guide/v550/running-report-asynchronously I see that I need to have a "parameters" dict. The example in the link shows the XML which is not all that useful since it's unclear exactly what the equivalent JSON should look like. The closest I could find is in this link: http://community.jaspersoft.com/documentation/jasperreports-server-web-services-guide/v56/modifying-report-parameters. Now, I am sending the equivalent of that to the server (and every other permutation I can think of), and I continue to get a "400 Client Error: Bad Request" back. I could really use an exact example of the python code to generate the required "parameters" parameter for say "my_parameter_1="test_value_1".
Here is my current POST data (with a few params missing for brevity). I know this is correct since the report works fine if I omit the "parameters" parameter:
{
'outputFormat': 'pdf',
'parameters': [{'name': 'ReportID', 'value': ['my_value_1']}],
'async': 'true',
'pages': '',
'interactive': 'false'
}
Nice Job there Staggart. I got it now. Because I wasn't reading with max. scrutinity, I wasted some additional time. So the interested coder is not only advised to be aware of the nested, syntactictally interesting reportParameter-property, but especially that the value-property inside that is an array. I suppose one could pass some form of Lists/Arrays/Collections here?
What irritated me was, if I should construct more than one "reportParameter" property, but that would be nonsense according to
Does JSON syntax allow duplicate keys in an object.
So just for the record, how to post multiple parameters:
{
"reportUnitUri": "/reports/Top10/Top10Customers",
"async": true,
"freshData": true,
"saveDataSnapshot": false,
"outputFormat": "pdf",
"interactive": false,
"ignorePagination": true,
"parameters": {
"reportParameter": [
{
"name": "DATE_START_STRING",
"value": ["14.07.2014"]
},
{
"name": "DATE_END_STRING",
"value": ["14.10.2014"]
}
]
}
}
If someone accidently is struggling with communicating with jasper via REST and PHP. Do yourself a favour and use the Requests for PHP instead of pure CURL. It even has a fallback for internally using Sockets instead of CURL, when latter isn't available.
Upvote for you Staggart.
OK, thanks to rafkacz1 # http://community.jaspersoft.com/questions/825719/json-equivalent-xml-post-reportexecutions-rest-service who posted an answer, I figured it out. As he report there, the required format is:
"parameters":{
"reportParameter":[
{"name":"my_parameter_1","value":["my_value_1"]}
]
}
Pay particular attention to the plurality of "reportParameter".
Here is an example that worked for me. Im using Python 2.7, and the community edition of Jaspersoft. Like the C# example above, this example also uses the rest v2 which made it very simple for me to download a pdf report quickly
import requests
sess = requests.Session()
auth = ('username', 'password')
res = sess.get(url='http://your.jasper.domain:8080/jasperserver/', auth=auth)
res.raise_for_status()
url = 'http://your.jasper.domain:8080/jasperserver/rest_v2/reports/report_folder/sub_folder/report_name.pdf'
params = {'Month':'2', 'Year':'2017','Project': 'ProjectName'}
res = sess.get(url=url, params=params, stream=True)
res.raise_for_status()
path = '/path/to/Downloads/report_name.pdf'
with open(path, "wb") as f:
f.write(res.content)
Here's a full example about generate a report using Rest V2, in my case it's running on C#:
try {
var server = "http://localhost:8080/jasperserver";
var login = server + "/rest/login";
var report = "/rest_v2/reports/organization/Reports/report_name.pdf";
var client = new WebClient();
//Set the content type of the request
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
//Set the username and password
NameValueCollection parametros = new NameValueCollection();
parametros.Add("j_username", "jasperadmin");
parametros.Add("j_password", "123456");
//Request to login
client.UploadValues(login, "POST", parametros);
//Get session cookie
string session = client.ResponseHeaders.Get("Set-Cookie");
//Set session cookie to the next request
client.Headers.Add("Cookie", session);
//Generate report with parameters: "start" and "end"
var reporte = client.DownloadData(server + report + "?start=2015-10-01&end=2015-10-10");
//Returns the report as response
return File(reporte, "application/pdf", "test.pdf");
}catch(WebException e){
//return Content("There was a problem, status code: " + ((HttpWebResponse)e.Response).StatusCode);
return null;
}