How to bypass header from request into header in response in AWS API Gateway? - amazon-web-services

I have API Gateway endpoint, which is actually mock endpoint.
What I am trying to do is to make API to take Origin header from request and return the same value in response as Access-Control-Allow-Origin header.
So far I've tried to do the following:
Got to "Method Request" and add "Origin" header to the list
In "Method Execution" I am trying to map Access-Control-Allow-Origin to method.request.header.Origin, but I am getting an error message
Invalid mapping expression specified: Validation Result: warnings : [], errors : [Invalid mapping expression specified: method.request.header.Origin]
Thanks!

integration.request and integration.response only prepare the input to and output from the integration response. Therefore the integration request only supports additional input from the method.request and the integration response only supports additional input from the method response definitions.
Mapping the method.request parameters to method.response is currently not supported but definitely a valid and useful use case. I'll add it to our backlog, but unfortunately cannot commit to a timeline for when we plan on delivering this feature enhancement.
As a workaround, you could pass the Origin header to your integration endpoint which simply mirrors the input and passes it back to API Gateway. This way you should be able to return the value of the Origin request header as an Access-Control-Allow-Origin response header.
Hope this helps,
Jurgen, API Gateway

It can be done by input.param and context.responseOvverride methods
In Integration Response add a Mapping Template for proper Content-Type with a body like this:
#set($origin = $input.params('origin'))
#set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)
It should look like this:
Of course, it can also be added via Cloud Formation and x-amazon-apigateway-integration. Example part of yaml:
x-amazon-apigateway-integration:
responses:
default:
statusCode: "200"
responseTemplates:
application/json: |
#set($origin = $input.params('origin'))
#set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)
Hope that helps.

Related

APIGateway mapping header to path via proxy

I am trying to proxy a request though API gateway to an internal service.
My external request looks like:
Path: /resources
Headers: owner_id passed along which was decoded via an authorizer in a previous step.
The proxied endpoint I would like to hit is:
/owner/{owner_id}/resources
Is it possible to pull a header out and use this as a path parameter to the internal API?
Set an Endpoint URL like http://httpbin.org/anything/{owner_id}/blah1/blah2 in Integration Request
in the same Integration Request, add a Mapping Templates : "When there are not templates defined (recommended)) section, add a Content-Type : application/json with a template body of #set($context.requestOverride.path.owner_id = $input.params("owner_id"))
See also: https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html#input-variable-reference

AWS API Gateway: Handle both invalid URL and validation errors

I have an API gateway set up with an OpenAPI specification and a proxy lambda integration. Request validation is enabled, and also an authorizer lambda.
Let's say I have endpoints GET /foo and POST /bar. The integrations to these endpoints work well, and the requests are validated and authenticated.
The problem is this:
In order to send back any validation errors when an invalid request is made, e.g. with a missing request body property, I have the following response mapping:
x-amazon-apigateway-gateway-responses:
BAD_REQUEST_BODY:
statusCode: 400
responseTemplates:
application/json: |
{"message": "Invalid request body: $context.error.validationErrorString"}
This also works well. However, if I try to call an endpoint that doesn't exist (e.g. GET /baz), I get a very weird default error message from API gateway. From the past I remember getting a HTTP 403 with something like "missing API key" for invalid URLs, which is weird since it should render a 404, but now I get the even stranger body:
{
"message": "'eyJhbGciOiJSUzI <rest of JWT ...>' not a valid key=value pair (missing equal-sign) in Authorization header: 'Bearer eyJhbGciOiJSUzI <...>"
}
In other words, the JWT I send as my bearer token is passed back in an error message, saying it's not a key=value pair.
Thing is, my authorizer lambda is only connected to the valid endpoints (obviously), so it's not being called. But why is the default built-in API gateway route handler parsing my bearer token and deciding it's not a key=value pair (!)? For an endpoint that doesn't exist? I don't have any {proxy+} endpoint at all.
If I try to map all 403 responses (MISSING_AUTHENTICATION_TOKEN, INVALID_SIGNATURE, etc) to custom error messages, as described here, I get no result, despite docs saying the default response for missing URLs is MISSING_AUTHENTICATION_TOKEN. However, if I also override DEFAULT_4XX, it works, I can return a HTTP 404 with a "Not found" message. The problem is that as soon as I override DEFAULT_4XX, it also overrides my BAD_REQUEST_BODY response so that my validation error messages are lost. Apparently DEFAULT_4XX is not matched last, it takes precedence over BAD_REQUEST_BODY!
How can I set up API gateway so that I at the same time can:
Return 404 NOT FOUND for invalid endpoints such as GET /baz
Return 400 with the $context.error.validationErrorString variable for requests that failed validation
I've found this question that described a similar problem, but surely it's not required to create a {proxy+} integration and/or a dedicated separate lambda only to return a 404 error, this must be possible to achieve by configuration!?
I used the openAPI mock proxy (no lambda) solutions documented here: not a valid key=value pair (missing equal-sign) in Authorization header
It is working very well.

AWS API Gateway integration request Http headers not being passed to lambda

This is similar to this post API-Gateway Integration Request HTTP Header not mapping query string to header but I can't see any answer for it and all of the answers are not related to what the question is intended.
I am trying to add the integration request parameters in API Gateway, but whenever I set 'Http Headers' as shown here and 'Mapping template' as passthrough, I could not see that header when I log inside the lambda.
Also in the integration response I cannot reference it inside the integration header response parameters. The "integration.response.header.cokers" will be returned blank when I invoke the API. This is how I configured the integration response
Ultimately the solution here is to implement a lambda proxy integration.
A proxy integration in API Gateway tells API Gateway to simply forward all headers to the integration for processing, which means you will see all of those values in your lambda function.
NOTE: Lambda has to return a specific response format back to API Gateway if it's a proxy integration. Ultimately, the response should be something like:
{
'statusCode': 200,
'headers': {
'echo-proxy': True
},
'body': 'some payload'
}
What you are trying to do right now is map everything manually, which is a deprecated approach and usually you don't want to do that unless you absolutely have to because it's kind of a pain.
If you have to map the headers manually start by mapping them in the the method request so it can carry on to the next step and so on. Basically like this:
Method Request -> Maps variable to Integration Request -> Maps variable to Body Mapping Template -> Maps variable to actual request header
What you have in your screenshot for the Integration Request -> HTTP Headers is:
Name: cokers
Mapped from: 'blah'
However, "mapped from" should look something like "method.request.header.coker" which is a standardized path (meaning to get the value from the Method Request Header field with name "coker").
Once you have added the coker header to the Method Request, and the Integration Request HTTP Headers are mapped correctly, you have to implement a mapping template. Set the content-type to application/json with passthrough set to "When there are no templates defined(recommended)" and a simple mapping template:
{
"headers": {
"coker" : "$input.params('coker')"
}
}
That is the way my API is setup and it returns the following to me because I had my lambda function return the event as a json object back to API GW:
{"body": "{\"headers\": {\"coker\": \"mapped\"}}", "statusCode": 200}
NOTE: the value of my header "coker" in the request on the client side is "mapped"
UPDATED ANSWER
To map the original "coker" header to "coker2" (or any other name you want to give it) you simply set the name of the header in your mapping template like so:
{
"headers": {
"coker2" : "$input.params('coker')"
}
}
Then edit your lambda function to return "coker2" header and you should get a response like this:
{"body": "{\"headers\": {\"coker2\": \"mapped\"}}", "statusCode": 200}

AWS API Gateway: is it possible to include specific request body validation error in the response body?

I have an API Gateway POST endpoint that takes in a JSON request body. I have turned on the body request validator and added the request body model. However the error response I'm getting is only some generic message: "message": "Invalid request body" as defined in the Gateway responses. I'm wondering if it is possible to include the specific validation error in the response? In the logs it says specifically
Request body does not match model schema for content type application/json:
[object has missing required properties (["property1","property2",...])]
Is it possible to have something similar to this in the actual response? Thank you.
In Gateway response for error type BAD_REQUEST_BODY error status 400
set Application/json to {"message":$context.error.validationErrorString}
Ref
https://stackoverflow.com/a/48014686
AWS API Gateway will include more details only if the request payload format is valid, but parameters format is invalid:
{
"message": "Missing required request parameters: [p1]"
}
If the request payload is invalid, you will always receive the same message:
{
"message": "Invalid request body"
}
See the bottom of following page:
http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-validation-test.html
The only way you can get more details is through logs.
By the way, why do you want to send more details through your API, is it for development and debugging only? If yes, using logs is the way to go. You may have some log processing and storage solution to make your debugging easier (e.g. Splunk, Data Dog, Sumo Logic, etc.)
Otherwise, in general, returning too much of technical details in your API error messages is something to avoid.

Setting http response header from AWS lambda

My API Gateway/Lambda setup returns an HTTP response header:
Lambda uses callback function to return the value as part of a JSON
and the Integration Response maps it into a HTTP header (using integration.response.body)
With this solution, the values are sent back both in the body and the header.
How can I map headers from the Lambda response without duplicating the values in the response body?
If you have Lambda proxy integration enabled, you can set the response headers as part of Lambda output and API Gateway will return them as part of the HTTP response to the client.
Node.js example:
callback(null, {
"isBase64Encoded": false, // Set to `true` for binary support.
"statusCode": 200,
"headers": {
"header1Name": "header1Value",
"header2Name": "header2Value",
},
"body": "...",
});
where headers can be null or unspecified if no extra response headers are to be returned.
See Output Format of a Lambda Function for Proxy Integration.
and, if you DON'T have Lamba proxy integration enabled, you can add (and map) the response headers in the amazon API gateway console:
go to resources -> method execution -> method response -> add 'Access-Control-Allow-Origin' (or whatever) header for http status 200. Then go back to method execution -> integration response -> http status 200 -> set header mapping for 'Access-Control-Allow-Origin' to '*' (or whatever).
Solved this error...: "No 'Access-Control-Allow-Origin' header is present on the requested resource"
Since the question states that custom mappings are being used (using integration.response.body), it means Lambda Proxy Integrations are NOT being used. So, the solution, in this case, is to map the headers the way you are already doing.
To remove the headers duplication from the body part, use mapping template in the integration response and ignore headers in the mapping. I think you might be using pass through responses, that's why you are seeing duplicate headers.
See more documentation here: https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html