Use OpenAPI Components with AWS API Gateway - amazon-web-services

I am relatively new to AWS API Gateway. I am trying to make use of OpenAPI Components in the OpenAPI definition for the API Gateway.
I am trying to build reusable responses for the integration response as illustrated below.
This is a reusable component for 400 response (along with the mapping template for it):
components:
responses:
BAD_REQUEST:
statusCode: "400"
responseTemplates:
application/json: "#set($inputRoot = $input.path('$'))\n{ \n \"message\"\
: \"Invalid Request Body\"\n}"
And I am trying to use this under responses in the API Gateway Integration like below:
x-amazon-apigateway-integration:
<API_GATEWAY_CONFIG_GOES_HERE>
responses:
.*"BadRequest".*:
$ref: '#/components/responses/BAD_REQUEST'
When I deploy the whole CloudFormation stack I got that error and the stack could not be deployed:
Unable to put integration response on 'POST' for resource at path '/test_resource': Integration response status code must be non-empty
Any ideas?

I have spent a few days searching for this and the only possible way is YAML anchors:
You can check the code from:
How to re-use my x-amazon-apigateway-integration definition throughout Swagger YAML document?
https://github.com/aws/serverless-application-model/issues/228#issuecomment-564427077
Additionally, this official way from AWS doesn't seem to work as of now!

Related

GCP: API-Gateway Cors Issue and adding custom authentication

I have configured API-Gateway to call Cloud Function, also we have configured Load Balancer for this API-Gateway host. But we are facing CORS Issue when we invoke this Load balancer end point from our web application.
Question 1: Please guide me on how to add CORS support at API config open-api YAML file.
Question 2: How To add Custom authentication endpoint to this open-api config YAML file?
High level flow: webapp --> load balancer url --> API-Gateway --> CloudFunction
I have added CORS backend support at cloud function as per the GCP link: https://cloud.google.com/functions/docs/writing/http#authentication_and_cors
Cloud Function code as follows:
public class Demand implements HttpFunction {
private static final Logger logger = Logger.getLogger(Demand.class.getName());
// Use GSON (https://github.com/google/gson) to parse JSON content.
private static final Gson gson = new Gson();
#Override
public void service(HttpRequest request, HttpResponse response) throws Exception {
String contentType = request.getContentType().orElse("");
logger.info(() -> "contentType: " + contentType);
// Set CORS headers
// Allows GETs from any origin with the Content-Type
// header and caches preflight response for 3600s
response.appendHeader("Access-Control-Allow-Origin", "*");
System.out.println("Added preflight options request support::::::::::");
if ("OPTIONS".equals(request.getMethod())) {
System.out.println("OPTIONS::::::::::::::::");
response.appendHeader("Access-Control-Allow-Methods", "*");
response.appendHeader("Access-Control-Allow-Headers", "Content-Type");
response.appendHeader("Access-Control-Max-Age", "3600");
response.setStatusCode(HttpURLConnection.HTTP_NO_CONTENT);
return;
}
// Handle the main request.
BufferedWriter writer = response.getWriter();
writer.write("CORS headers set successfully!");
}
Open-API spec below:
---
info:
description: Sample API on API Gateway with a Google Cloud Functions backend
title: trigger-post
version: 1.0.0
paths:
/triggerondemand:
post:
consumes:
- application/json
operationId: triggerondemand
parameters:
- description: triggerondemand.
in: body
name: ondemand
schema:
properties:
fileStatus:
type: string
type: object
responses:
'201':
description: Created
summary: triggerondemand
x-google-backend:
address: >-
https://us-east1-neodev-305805.cloudfunctions.net/demand
produces:
- application/json
schemes:
- https
swagger: '2.0'
Browser Error as follows:
Access to XMLHttpRequest at 'https://apitest.dev.app.com/triggerondemand' from origin 'https://dataplatform.dev.app.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Thanks in advance
The answer to both your questions is that this is not possible at the moment.
The GCP API Gateway does not support the handling of CORS at the moment, although it is in the roadmap to be implemented, but you can use a workaround to do that as you can see in this community answer.
On regards to custom authentication, as I decribed in my answer here:
Unfortunately the GCP API Gateway does not provide such option for custom authentication, in order to authenticate using the API Gateway you have to use one of the alternate authentication methods provided in the documentation.

AWS API Gateway: How to remove/replace query string parameter in HTTP Proxy Passthrough integration?

When I query my Invoke URL as https://xxx.execute-api.yyy.amazonaws.com/test/q?apiKey=AAA with my below setup my backend receives a call as https://api.mysite.com/q?apiKey=AAA&apiKey=111: one apiKey=AAA comes from the client, the second one - apiKey=111 comes from the Integration Request configuration.
Question:
What/How should I configure an integration that apiKey=AAA either removed from the client call or replaced on the integration step with 111 value so that only one apiKey comes to the backend?
Note:
with proxy passthrough integration the Mapping Templates are not available;
the reason for such configuration is that my legacy backend has a big amount of endpoints which is not possible to configure individually.
My setup:
I have created a new REST API.
Then I have created a new Configure as a Proxy resource named proxy with a Resource Path /{proxy+} with the following setup for ANY method as a proxy integration:
Integration type HTTP Proxy
Endpoint URL: https://api.mysite.com/{proxy}
Content Handling: Passthrough
As a next step, I have configured an Integration Request for my /{proxy+} - ANY by adding a new query string to the URL Query String Parameters section:
Name: myApiKey
Mapped from: '111'
Then I click Deploy API to test stage and getting Invoke URL, let's say: https://xxx.execute-api.yyy.amazonaws.com/test.
Even with Proxy Integration, we can still override Request & Response.
Here is the blog. Let me try to summarize.
Ensure that Use Proxy Integration is unchecked
Simple VTL template in Mapping Template to replace apiKey queryParameter.
#set($newApiKey = "abcd")
$input.json("$")
#set($context.requestOverride.querystring.apiKey = $newApiKey)
Add Method Responses example response codes 200, 400 and 500.
Add Integration Response for each status code for each response codes for example http status for 2xx 2\d{2} with pass through behaviour.
Lets say we have a proxy setup for path /someapi/sompath. Above template will replace /someapi/sompath?apiKey=100 to {proxy}?apiKey=abcd

AWS API Gateway supports CORS for OPTIONS only when using SAM (without Lambda proxy integration)

I'm using AWS Serverless for building a small site with around 15 Lambda functions.
My Cloudformation stack is completely built using SAM.
I'm NOT using Lambda proxy integration.
The Api section in the SAM yaml template config looks like this:
AppApi:
Type: AWS::Serverless::Api
Properties:
Cors:
AllowMethods: "'*'"
AllowHeaders: "'Content-Type'"
AllowOrigin: "'*'"
...........More Stuff..........
When I deploy this SAM yaml template, I see that my ApiGateway created the OPTIONS verb for all methods and when I shoot a request with the OPTIONS verb, I do see the CORS headers correctly.
The problem is that the other verbs (e.g. POST) don't add those headers to their response as the OPTIONS request did and when I run my api from the browser I get the cross origin policy error in my console.
So my current workaround was to add the CORS header using integrated responses to specific status codes, but I cannot and dont want to handle that for 15 methods and I want to support all response status codes (e.g. 4xx\5xx etc.).
My questions:
Am I doing anything wrong here or is this a SAM bug?
If this is a bug, is there any workaround other from adding the headers using integrated responses (or from my code)?
Is there a way I can add headers "globally" from an Api Gateway? Or support some kind of global integrated responses?
If you are using Lambda with Proxy Integrations, you need to specify the CORS Origin in your HTTP response.
For Lambda or HTTP proxy integrations, you can still set up the
required OPTIONS response headers in API Gateway. However, you must
rely on the back end to return the Access-Control-Allow-Origin headers
because the integration response is disabled for the proxy
integration.
https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html
All responses from Lambda need to have these headers and status code, but you could extract that to a shared library to reduce code duplication. Errors handled by API-G will have the headers added automatically.
You probably already have this, but the NodeJS pattern is like this:
var response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin" : "*"
},
body: JSON.stringify({
someReturnData
})
};
callback(null, response);
If you really don't want to do this then you can turn off Lambda-Proxy Integration, but that means that all request response payloads need to be handled in API-G instead of Lambda. IMO this provides much less flexibility and more configuration required to achieve the same results.
Here is an interesting comparison of the two approaches.

How to bypass header from request into header in response in AWS API Gateway?

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.

AWS API Gateway : Use 302 redirect and set-cookie header

I used AWS API Gateway to redirect in response.
simple flow :
aaa.com ====> API Gateway & Lambda ==[302 redirect]==> bbb.com
It worked well when following the blog. However, I couldn't set cookie at bbb.com.
I followed the blog and defined another “Set-Cookie” header. My Lambda code snippet listed below.
context.succeed({
location : "http://192.168.173.193:3030",
setCookie: "path=/;sessionID=1234;domain=null;"
});
Did you update your Response Parameters?
In that blog post notice the responseParameters section of the Swagger Example.
responseParameters:
method.response.header.Location: "integration.response.body.location"
You need to add another line to that mapping the Set-Cookie parameter. Something like:
responseParameters:
method.response.header.Location: "integration.response.body.location"
method.response.header.Set-Cookie: "integration.response.body.setCookie"