How do I map path parameters from an API Gateway API to the Request Object of a Java Lambda - amazon-web-services

I have a lambda, written in Java, that accepts a Request Object of the structure
{
"id": "be1c320a-144f-464d-b32c-38ec7fb4445b",
"userId": "foobar"
}
When I call this Lambda through the test interface with such an object, it works fine.
I want to create an API where a GET request to
/users/foobar/items/be1c320a-144f-464d-b32c-38ec7fb4445b
i.e. of the form
/users/{userId}/items/{id}
calls this Lambda.
I have created the API resources /users, {userId}, items, and {id} appropriately.
And I have created the GET method (on /users/{userId}/items/{id})and associated it to the lambda.
When I test the API, it invokes the lambda, but with null values in the request. I can see it package the path as {"id":"be1c320a-144f-464d-b32c-38ec7fb4445b","userId": "foobar"} in the logs, but that's not being sent in the body.
I have tried creating a template map (and have tried RTFM), but cannot see how to map path parameters to a body.
How do I achieve this mapping?

I think your Request Object structure may not be properly configured. There may be a few ways to configure this. Here is some information that has helped me.
How to pass a querystring or route parameter to AWS Lambda from Amazon API Gateway - Demonstrates this mapping (albeit with python). However, taking the top response, if you enable "Use Lambda Proxy integration", you can similarily do this with Java as so:
#Override
public Object handleRequest(APIGatewayProxyRequestEvent input, Context context) {
Map<String, String> pathParameters = input.getPathParameters();
String id = pathParameters.get("id");
String userId = pathParameters.get("userId");
// Handle rest of request..
}
This is a tuturial using the serverless framework to create an Api with Java. This tutorial similarily accesses the pathParameters by parsing the input rather than using the APIGatewayProxyRequestEvent java class.
#Override
public Object handleRequest(Map<String, Object> input, Context context) {
try {
// get the 'pathParameters' from input
Map<String,String> pathParameters = (Map<String,String>)input.get("pathParameters");
String id = pathParameters.get("id");
String userId = pathParameters.get("userId");
} catch (Exception ex) {
logger.error("Error in retrieving product: " + ex);
}
}

Use a mapping template.
First, in the Method Request section, you should see userId and id as Request Paths
Then, in the Integration Request, do not choose Proxy Integration.
Then in the Mapping Templates section, add a new mapping template for application/json of the form
{
"id" : "$method.request.path.id",
"userId" : "$method.request.path.user_id"
}

Related

Spring cloud function accessing query parameters

Is it possible to access to query parameters that are forwarded from aws apigateway to awslamdba implemented using spring cloud function. the following is my implementation.
I call this using http get request
example: http://sampledomain.com/test?param1=value
How can I retrieve param1 value in the method below
#Bean
public Function<Message<String>,String> reverseString2() {
return value1 -> {
System.out.println("headers..."+value1.getHeaders());
value1.getHeaders().entrySet().forEach(entry -> System.out.println(entry.getKey() + " - " + entry.getValue()));
return "example";
} ;
}
I don't think the Message supports the Query Parameters. You can try either of the options -
Change your Function to Function<APIGatewayProxyRequestEvent, Message<String>> and then you can access the query parameters using apiGatewayProxyRequestEvent.getQueryStringParameters()
If you want to use Function<Message<String>, Message<String>> , you can change the HttpMethod to POST and send the message in the Request body. Message.getPayload() will provide you with the content.

How to pass event info from aws API Gateway get to Lambda?

How do I refer to API Gateway GET query string parameters in a Lambda function ?
When I test I can use my local test event with "username": "larry"
When I test with a post I can use the body parameters as the event with "username": "larry"
With a get request, I don't have a body. How could I use query string parameters and then refer to them in the request. What event or other attribute do I use to get at the query param or what setting or change do I need to make?
Method request
Integration request
Query String
When testing I've referred to event["username", what do I do for an API request passing it as a query string parameter?
Login and click to API gateway and click on method - GET method
Go to Method Execution - select URL Query String Parameter and add query String parameter username
Now go to Integration Request tab Choose Body Mapping Template,
"content type application/json"
Generate Template like below
{
"username": "$input.params('username')"
}
Now write ;ambda which accept key value in pair .
module.exports.get = (event, context, callback) => {
const { username } = event.pathParameters;
console.log("username", username);
}
Now go and deploy your api on apigetway and find url and hit in browser example
https://xxx.yyy-api.us-east-2.amazonaws.com/prod/username?vaquarkhan
Hope it will help
https://docs.aws.amazon.com/de_de/apigateway/latest/developerguide/welcome.html
https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-set-up-simple-proxy.html#api-gateway-set-up-lambda-proxy-integration-on-proxy-resource

How to map querystring and header to AWS C# lambda function parameter

I have AWS Gateway REST API that takes 2 querystring parameters
https://xxxxxx.xxxx.us-east-1.amazonaws.com/dev/pets?type=dog&page=1
The caller of the API also include x-api-key in the header. I want API gateway to pass querystring parameters and x-api-key to lambda function. So in AWS API Gateway Console i have configured the Integration Request as below
The lambda function looks like this
namespace AWSLambda1
{
public class Function
{
public string FunctionHandler(LambdaRequest request, ILambdaContext context)
{
return string.Format("{0},{1},{2}", request.Type, request.Page, request.ApiKey);
}
}
}
public class LambdaRequest
{
public string Type { get; set; }
public string Page { get; set; }
public string ApiKey { get; set; }
}
Issues
1> When lambda function receives the request, the Type and Page properties are coming as NULL.
2>As per documentation API Gateway can map the http header using the naming convention method.request.header.{param_name}, however when i try to set map from as method.request.header.x-api-key it throws error
Invalid mapping expression specified: Validation Result: warnings :
[], errors : [Invalid mapping expression parameter specified:
method.request.header.x-api-key]
I am not sure how do i map these query string and header to C# lambda object
(Please note that i have already gone through SO post that suggest to JObject as parameter for lambda function. But it only works for me if i enable Use Lambda Proxy integration in Integration Request. In such case API gateway pass all the information to lambda. This might work for me but i am trying to avoid passing unwanted information to lambda function)
Adding Full answer here.
Header Issue
First thing, you need to make sure header entry is added in Method Request and then you can go map that in Integration Request with mapping method.request.header.x-api-key. The error is happening because you did not add in Method Request section but trying to configure it in Integration Request only.
Lambda Payload Issue
It looks like you are not using Lambda Proxy Integration. If you use Lambda Proxy Integration then you will get full event JSON object event data to Lambda. Similar to answer given in post you have shared. This JSON object will contains headers, queryparameters, path variables, url, request body etc.,. If you want to see some sample on how it looks, just go and create API Gateway Test Event on Lambda.
Now, if you do not want to use Lambda Proxy Integration but want to limit what is being sent to Lambda then you will have to create Integration Mapping Template to send only required info to Lambda such as headers, payload, query params etc., from API Gateway.
Sample Integration Template.
{
"body" : $input.json('$'),
"headers": {
#foreach($header in $input.params().header.keySet())
"$header": "$util.escapeJavaScript($input.params().header.get($header))" #if($foreach.hasNext),#end
#end
},
"method": "$context.httpMethod",
"params": {
#foreach($param in $input.params().path.keySet())
"$param": "$util.escapeJavaScript($input.params().path.get($param))" #if($foreach.hasNext),#end
#end
},
"query": {
#foreach($queryParam in $input.params().querystring.keySet())
"$queryParam": "$util.escapeJavaScript($input.params().querystring.get($queryParam))" #if($foreach.hasNext),#end
#end
}
}
Reference -
https://kennbrodhagen.net/2015/12/06/how-to-create-a-request-object-for-your-lambda-event-from-api-gateway/
https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html

How to filter an REST Result by sending custom request header parameter

i have an ASP.NET Core 1.1 WebApi Endpoint like this one:
[ApiVersion("1.0")]
[Route("api/[controller]")]
public class SampleController : Controller
{
[HttpGet]
public IActionResult Get()
{
...
}
}
It returns a collection of 'Sample'-Objects to the caller.
Now i do like to send within the Request Header a Custom Attribute like 'App-Type' which let the Endpoint know which App asks for Data. But what is to do that the endpoint fetches this Attribute so that i have it as variable within the function?
If you want a parameter in a controller action that reads from the headers, you should use [FromHeader] attribute, in your case it will be like [FromHeader(Name="Accept-Language")]. More information in https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding

How to get the HTTP method in AWS Lambda?

In an AWS Lambda code, how can I get the HTTP method (e.g. GET, POST...) of an HTTP request coming from the AWS Gateway API?
I understand from the documentation that context.httpMethod is the solution for that.
However, I cannot manage to make it work.
For instance, when I try to add the following 3 lines:
if (context.httpMethod) {
console.log('HTTP method:', context.httpMethod)
}
into the AWS sample code of the "microservice-http-endpoint" blueprint as follows:
exports.handler = function(event, context) {
if (context.httpMethod) {
console.log('HTTP method:', context.httpMethod)
}
console.log('Received event:', JSON.stringify(event, null, 2));
// For clarity, I have removed the remaining part of the sample
// provided by AWS, which works well, for instance when triggered
// with Postman through the API Gateway as an intermediary.
};
I never have anything in the log because httpMethod is always empty.
The context.httpMethod approach works only in templates. So, if you want to have access to the HTTP method in your Lambda function, you need to find the method in the API Gateway (e.g. GET), go to the Integration Request section, click on Mapping Templates, and add a new mapping template for application/json. Then, select the application/json and select Mapping Template and in the edit box enter something like:
{
"http_method": "$context.httpMethod"
}
Then, when your Lambda function is called, you should see a new attribute in the event passed in called http_method which contains the HTTP method used to invoke the function.
API Gateway now has a built-in mapping template that passes along stuff like http method, route, and a lot more. I can't embed because I don't have enough points, but you get the idea.
Here is a screenshot of how you add it in the API Gateway console:
To get there navigate to AWS Console > API Gateway > (select a resource, IE - GET /home) > Integration Request > Mapping Templates > Then click on application/json and select Method Request Passthrough from dropdown shown in the screenshot above
I had this problem when I created a template microservice-http-endpoint-python project from functions.
Since it creates an HTTP API Gateway, and only REST APIs have Mapping template I was not able to put this work. Only changing the code of Lambda.
Basically, the code does the same, but I am not using the event['httpMethod']
Please check this:
import boto3
import json
print('Loading function')
dynamo = boto3.client('dynamodb')
def respond(err, res=None):
return {
'statusCode': '400' if err else '200',
'body': err.message if err else json.dumps(res),
'headers': {
'Content-Type': 'application/json',
},
}
def lambda_handler(event, context):
'''Demonstrates a simple HTTP endpoint using API Gateway. You have full
access to the request and response payload, including headers and
status code.
To scan a DynamoDB table, make a GET request with the TableName as a
query string parameter. To put, update, or delete an item, make a POST,
PUT, or DELETE request respectively, passing in the payload to the
DynamoDB API as a JSON body.
'''
print("Received event: " + json.dumps(event, indent=2))
operations = {
'DELETE': lambda dynamo, x: dynamo.delete_item(**x),
'GET': lambda dynamo, x: dynamo.scan(**x),
'POST': lambda dynamo, x: dynamo.put_item(**x),
'PUT': lambda dynamo, x: dynamo.update_item(**x),
}
operation = event['requestContext']['http']['method']
if operation in operations:
payload = event['queryStringParameters'] if operation == 'GET' else json.loads(event['body'])
return respond(None, operations[operation](dynamo, payload))
else:
return respond(ValueError('Unsupported method "{}"'.format(operation)))
I changed the code from:
operation = event['httpMethod']
to
operation = event['requestContext']['http']['method']
How do I get this solution?
I simply returned the entire event, checked the JSON and put it to work with the correct format.
If event appears an empty object, make sure you enabled proxy integration for the method. Proxy integration for an HTTP method adds request information into event.
See Use Lambda Proxy integration on API Gateway page.
If you are using API gateway, http method will be automatically passed to the event parameter when the lambda is triggered.
export const handler: Handler<APIGatewayProxyEvent> = async (
event: APIGatewayEvent,
context: Context
): Promise<APIGatewayProxyResult> => {
const httpMethod = event.httpMethod;
...
}