AWS API Gateway Method Response Status - amazon-web-services

I've seen other responses for similar questions but am horribly stuck.
Trying to set a HTTP response in API Gateway (APIGW) from a lambda function.
I get the below from hitting the APIGW end-point:
{"code":404,"body":"No products found.","statusCode":0,"successful":false}
When I try to map this to a 404 from APIGW, it never catches despite having tried just about every permutation of the response. The latest one I have in there was (in integration response):
Lambda regex: .*"404".*
Body mapping: $input.path('$')
Used a string in regex as the MIME type isn't being set to json even though the response looks like it. Have tried all sorts of variants for the body mapping.
This seems to work flawlessly for most other people but no dice; any help is appreciated.

Looks like our fancy lambda is the issue; APIGW is looking for a defined response structure (errorMessage) and handles the response as-expected once provided.

Have you heard of Lambda Proxy Integration?
With this you don't need to do all those regular expression, as the whole request/response is parse to your lambda.
You control the status code by your lambda code instead of configuring the API Gateway.

Related

Slack slash-command through AWS API Gateway to AWS Lambda (Python versus Java)

I am trying to connect a Slack slash-command to an AWS Lambda (through the AWS API Gateway).
I was able to adapt the Hello, World blueprint (written in Python) in the Lambda tutorial section. I set up an API gateway as a trigger, then had Slack POST the slash-command to the API endpoint. I had to manually decode the base64 body, then use parse_qs to convert the query string-like POST body into a dictionary, where I could then access it just fine.
My real Lambda code is currently in Java, but I've started with the java-basic sample app from the Developers Guide. I built the app, uploaded the jar, and confirmed the correct handler was being called. I set up another API gateway and pointed a different Slack slash-command at the new endpoin. It fails.
The log looks like:
java.lang.RuntimeException: An error occurred during JSON parsing
Caused by: java.io.UncheckedIOException: com.amazonaws.lambda.thirdparty.com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token
at [Source: (ByteArrayInputStream); line: 1, column: 1]
I'm guessing this means Slack is sending the same query string-like argument in the POST body, and for some reason, something is expecting JSON input, not just text. I don't understand why the Python handler was okay with building up an event dictionary and making the Lambda decode the POST body, whereas the Java handler is never getting called, but is dying before that when attempting to deserialize the POST body, thinking it's JSON.
Both Lambdas and API gateways were set up with the usual defaults, AFAICT.
I solved the problem by switching to using the HandlerStream example. I can then get the "body" from the event, Base64.decodeBase64 it, then unpack the form parameters with UriParameterMap.parse.
I then process the incoming text that came from the Slack slash command and then return a string of JSON that Slack expects.

Geolocation service with AWS API Gateway and Lambda

What we are trying to do
We are trying to set up a very simple Geolocation service with API Gateway and Lambda.
Very similar to https://ipstack.com/, but we don't want to use an external service as we believe it could be an issue in some jurisdictions to send a non-anonymized IP address to a service we don't control (before getting the user's consent).
Would like to have a simple api https://location.my-site.com that returns the country (for GDPR, cookies, etc purposes).
Now it seems that there is a light Cloudfront behind API Gateway that would produce the header "Cloudfront-Viewer-Country", which would be very simple and achieve what we need. i.e. lambda receives Cloudfront-Viewer-Country and just sends it back.
What we have tried
I have seen solutions such as this one: Build a Geolocation API using AWS Lambda and MaxMind, but I struggle to see why deploying an RDS and maintaining the MaxMind database would make sense for us, if it is already available from Cloudfront-Viewer-Country.
I have seen this question: Accessing cloudfront-viewer-country header in AWS API Gateway using HTTP Proxy?, and tried implementing the answer from Michael - sqlbot. But I cannot seem to access the headers.
I have also tried what is suggested in this post, but I can't seem to access the value of Cloudfront-Viewer-Country either.
What we are doing (in conjunction with 'What we have tried')
To access and check if the header is available I am using the following python lambda function
import json
def lambda_handler(event, context):
response = {
'status': '200',
'statusDescription': 'Found',
'headers': {
'location' : [ {
'event': json.dumps(event)
} ]
}
}
return response
What the problem is
but the event json dump doesn't contain Cloudfront-Viewer-Country.
I suspect I'm doing something wrong but I really can't figure it out. Any pointer would be very much appreciated.
Thank you
I was able to get access to Cloudfront-Viewer-Country by setting a Endpoint Type = Edge optimized.
I could not get it to work with Endpoint Type = Regional or with http api gateway.

AWS API GATEWAY empty body transformation

I am facing an issue, I cannot succed to solve it after few hour, I am hopping you guys can help :)
I have this AWS lambda function (using python):
It put item into my dynamodb, when I test directly in lambda it works well
Here is my dynamodb line
I created an API with AWS API GATEWAY as a "POST" type, then I set the integration request as followed :
and Content-Type : application/json
But when I try to test it on API GATEWAY (or postman etc) I get the following error :
I noticed that
But I don't know where the transformation come from neither how to solve it,
Then again, thank you so much for any help !

Can AWS API Gateway support `application/x-www-form-urlencoded` with body and query string parameters?

Numerous services can accept query string parameters in the URL when a POST request is made with Content-Type: application/x-www-form-urlencoded and other parameters in the body, but it seems AWS API Gateway cannot while also accepting query string parameters.
When I call the AWS API Gateway with a POST Mapping Template for application/x-www-form-urlencoded and query string URL parameters (with a Lambda function), I get the following error:
{
"message":"When Content-Type:application/x-www-form-urlencoded,
URL cannot include query-string parameters (after '?'):
'/prod/webhook?inputType=wootric&outputType=glip&url=...'"
}
Here is an example cURL:
curl -XPOST 'https://{myid}.execute-api.{myregion}.amazonaws.com/prod/webhook? \
inputType=wootric&outputType=glip&url=https://hooks.glip.com/webhook/ \
11112222-3333-4444-5555-666677778888' \
-d "#docs/handlers/wootric/event-example_response-created.txt" \
-H 'Content-Type: application/x-www-form-urlencoded' -v
The specific goal is to get a Wootric webhook event posted to a Lambda function using a URL with query string parameters.
You can get the code here:
https://github.com/grokify/chathooks
The Wootric event body file is here:
https://raw.githubusercontent.com/grokify/chathooks/master/docs/handlers/wootric/event-example_response-created.txt
The GitHub issue is here:
https://github.com/grokify/chathooks/issues/15
The error message seems pretty definitive but I wanted to ask:
Is there a workaround to configure an API Gateway to support both?
Is there a standards-based reason why AWS would not support this or is this just a design decision / limitation?
If there's no solution to this, is there a good lightweight solution other than deploying a hosted server solution like Heroku. Also, do other cloud services support this with their API gateway + cloud functions, like Google?
Some examples showing support for both:
jQuery example: jQuery send GET and POST parameters simultaneously at AJAX request
C# example: Accessing query string variables sent as POST in HttpActionContext
Yes,there is a workaround and the key issue is to set the mapping template that will convert string into json . Very detailed example shown in
API Gateway any content type.
Please set the request property as "Content-Type", "application/json" for your HttpURLConnection like below
connection.setRequestProperty("Content-Type", "application/json");
I had a similar problem, with a 3rd party provider using web hooks. It turns out that my provider is transforming the url path from UPPERCASE to LOWERCASE. Example the endpoint should be apigateway.com/dev/0bscur3dpathRANDOM instead apigateway.com/dev/0bscur3dpathRANDOM. You get the point.
I'm not sure if I got the point in question correctly, but if you want to access the request body that is encoded as application/x-www-form-urlencoded(or anything, actually) in your Lambda function, you should use LAMBDA_PROXY request integration type (aka tick "Use Lambda Proxy integration" checkbox) when creating a method for your resource. Then you can access the request body in event.body field as a plain text in your lambda function and parse it manually.

API Gateway - Get StatusCode

This should have been such a simple issue and I don't understand why it hasn't come up through all my searching (maybe it's just been a long day).
I have an API Gateway API setup, and I am adding a Body Mapping Template to my Integration Response for a 400* error group: see image -
All I would like to get is the StatusCode of the current response (as this is a 400* group - e.g. 401 / 403 / 404 etc.)
The closest I came was through this site: AWS help documentation and I thought I would be able to use something like $context.statusCode - but no luck.
Am I going crazy, or is this just not something required often?
PS - Making changes to any Lambda functions being called, is not an option.
Thanks
There's currently no mapping template variable in API Gateway dedicated to the integration response status code.
We will certainly add this as a feature request.
At current time you are limited to hardcoding the status code value in your response templates. You would either need to define generic status codes (i.e "4XX") or define integration responses for every status code you want to capture. While this seems tedious, this could be managed relatively easily in a Swagger template.
At current time the only way to see the integration response status code is via CloudWatch Logs.
Thanks,
Ryan / Amazon API Gateway
If you are sending error codes from your server then you can easily map them.
I have done something similar but I have used different trick to do. I used to send my own error entities and codes from server.
You have to map those error entities and error codes coming from server to the response that comes from amazon servers. I will try and explain what I mean by this. Api Gateway doesn't send response coming from your own server to the client automatically. You have to map those responses. For example, map 200 as a SUCESS and response entity will be default, that is whatever coming from server.
Now, we default success response is managed but what about error codes and error entities. You have to map them manually.
There are two ways you can do this,
One is manual, go to your api. Create error entities or models. Map them manually for each response code.
This one uses swaggger,
Solution is to import swagger specification of error entities. Add response templates to the swagger specification and let amazon do their job.
I can help you more with swagger. It depends how you are setting up your api on amazon.
Visit this for amazon extenstions to swagger,
http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions.html#api-gateway-swagger-extensions-integration-response