enabling CORS for AWS API gateway with the AWS CDK - aws-cloudformation

I'm trying to build an application with the AWS CDK and if I were to build an application by hand using the AWS Console, I normally would enable CORS in API gateway.
Even though I can export the swagger out of API Gateway and have found numerous options to generate a Mock endpoint for the OPTIONS method I don't see how to do this with the CDK. Currently I was trying:
const apigw = require('#aws-cdk/aws-apigateway');
where:
var api = new apigw.RestApi(this, 'testApi');
and defining the OPTIONS method like:
const testResource = api.root.addResource('testresource');
var mock = new apigw.MockIntegration({
type: "Mock",
methodResponses: [
{
statusCode: "200",
responseParameters : {
"Access-Control-Allow-Headers" : "string",
"Access-Control-Allow-Methods" : "string",
"Access-Control-Allow-Origin" : "string"
}
}
],
integrationResponses: [
{
statusCode: "200",
responseParameters: {
"Access-Control-Allow-Headers" : "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'",
"Access-Control-Allow-Origin" : "'*'",
"Access-Control-Allow-Methods" : "'GET,POST,OPTIONS'"
}
}
],
requestTemplates: {
"application/json": "{\"statusCode\": 200}"
}
});
testResource.addMethod('OPTIONS', mock);
But this doesn't deploy. The error message I get from the cloudformation stack deploy when I run "cdk deploy" is:
Invalid mapping expression specified: Validation Result: warnings : [], errors : [Invalid mapping expression specified: Access-Control-Allow-Origin] (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException;
Ideas?

The recent change has made enabling CORS simpler:
const restApi = new apigw.RestApi(this, `api`, {
defaultCorsPreflightOptions: {
allowOrigins: apigw.Cors.ALL_ORIGINS
}
});

Haven't tested this myself, but based on this answer, it seems like you would need to use a slightly different set of keys when you define your MOCK integration:
const api = new apigw.RestApi(this, 'api');
const method = api.root.addMethod('OPTIONS', new apigw.MockIntegration({
integrationResponses: [
{
statusCode: "200",
responseParameters: {
"method.response.header.Access-Control-Allow-Headers": "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'",
"method.response.header.Access-Control-Allow-Methods": "'GET,POST,OPTIONS'",
"method.response.header.Access-Control-Allow-Origin": "'*'"
},
responseTemplates: {
"application/json": ""
}
}
],
passthroughBehavior: apigw.PassthroughBehavior.Never,
requestTemplates: {
"application/json": "{\"statusCode\": 200}"
},
}));
// since "methodResponses" is not supported by apigw.Method (https://github.com/awslabs/aws-cdk/issues/905)
// we will need to use an escape hatch to override the property
const methodResource = method.findChild('Resource') as apigw.cloudformation.MethodResource;
methodResource.propertyOverrides.methodResponses = [
{
statusCode: '200',
responseModels: {
'application/json': 'Empty'
},
responseParameters: {
'method.response.header.Access-Control-Allow-Headers': true,
'method.response.header.Access-Control-Allow-Methods': true,
'method.response.header.Access-Control-Allow-Origin': true
}
}
]
Would be useful to be able to enable CORS using a more friendly API.

Edit: With updates to CDK it is no longer necessary to use an escape hatch. Please see other answers as they are much cleaner.
Original answer:
This version, originally created by Heitor Vital on github uses only native constructs.
export function addCorsOptions(apiResource: apigateway.IResource) {
apiResource.addMethod('OPTIONS', new apigateway.MockIntegration({
integrationResponses: [{
statusCode: '200',
responseParameters: {
'method.response.header.Access-Control-Allow-Headers': "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent'",
'method.response.header.Access-Control-Allow-Origin': "'*'",
'method.response.header.Access-Control-Allow-Credentials': "'false'",
'method.response.header.Access-Control-Allow-Methods': "'OPTIONS,GET,PUT,POST,DELETE'",
},
}],
passthroughBehavior: apigateway.PassthroughBehavior.NEVER,
requestTemplates: {
"application/json": "{\"statusCode\": 200}"
},
}), {
methodResponses: [{
statusCode: '200',
responseParameters: {
'method.response.header.Access-Control-Allow-Headers': true,
'method.response.header.Access-Control-Allow-Methods': true,
'method.response.header.Access-Control-Allow-Credentials': true,
'method.response.header.Access-Control-Allow-Origin': true,
},
}]
})
}
I also ported the same code to python using his version as a guidepost.
def add_cors_options(api_resource):
"""Add response to OPTIONS to enable CORS on an API resource."""
mock = apigateway.MockIntegration(
integration_responses=[{
'statusCode': '200',
'responseParameters': {
'method.response.header.Access-Control-Allow-Headers':
"'Content-Type,\
X-Amz-Date,\
Authorization,\
X-Api-Key,\
X-Amz-Security-Token,X-Amz-User-Agent'",
'method.response.header.Access-Control-Allow-Origin': "'*'",
'method.response.header.Access-Control-Allow-Credentials':
"'false'",
'method.response.header.Access-Control-Allow-Methods':
"'OPTIONS,\
GET,\
PUT,\
POST,\
DELETE'",
}
}],
passthrough_behavior=apigateway.PassthroughBehavior.NEVER,
request_templates={
"application/json": "{\"statusCode\": 200}"
}
)
method_response = apigateway.MethodResponse(
status_code='200',
response_parameters={
'method.response.header.Access-Control-Allow-Headers': True,
'method.response.header.Access-Control-Allow-Methods': True,
'method.response.header.Access-Control-Allow-Credentials': True,
'method.response.header.Access-Control-Allow-Origin': True
}
)
api_resource.add_method(
'OPTIONS',
integration=mock,
method_responses=[method_response]
)

BACKGROUND
I came across this answer while trying to implement the aws_api_gateway_integration_response in Terraform and accidentally came across the solution.
PROBLEM
I was getting this error message:
Invalid mapping expression specified: Validation Result: warnings : [], errors : [Invalid mapping expression specified: POST,GET,OPTIONS]
In the aws_api_gateway_integration_response resource I had the response_parameter key as:
response_parameters = {
"method.response.header.Access-Control-Allow-Headers" = "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token"
"method.response.header.Access-Control-Allow-Origin" = "*"
"method.response.header.Access-Control-Allow-Methods" = "POST,GET,OPTIONS"
# "method.response.header.Access-Control-Allow-Credentials" = "false"
}
I thought everything was fine as I assumed the double quotes were all that Terraform needed. However, that was not the case.
SOLUTION
I had to add a single quote around the values inside the double quote. Like this:
response_parameters = {
"method.response.header.Access-Control-Allow-Headers" = "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
"method.response.header.Access-Control-Allow-Origin" = "'*'"
"method.response.header.Access-Control-Allow-Methods" = "'POST,GET,OPTIONS'"
# "method.response.header.Access-Control-Allow-Credentials" = "false"
}

Related

Strapi Plugin localization

I need help figuring this out
debug: ⛔️ Server wasn't able to start properly.
[2022-09-22 11:30:06.580] error: Cannot read property 'routes' of undefined
TypeError: Cannot read property 'routes' of undefined
at Object.addCreateLocalizationAction
An error comes up when i add localization option for my strapi plugin and this is the content scheme, i installed the i18n but it still didnt work
module.exports = {
kind: "collectionType",
collectionName: "tests",
info: {
singularName: "test",
pluralName: "tests",
displayName: "test"
},
options: {
"draftAndPublish": true
},
pluginOptions: {
i18n: {
localized :true
}
},
attributes: {
name: {
pluginOptions: {
i18n: {
localized: true
}
},
type: "string",
required: true
},
}
}

AWS CDK: Can't define Content-Type in AWS API Gateway Integration Response

I'm trying to add a GET Response to my API Gateway with AWS CDK.
However, I get this Error when I do cdk deploy:
Invalid mapping expression specified: Validation Result: warnings : [], errors : [Invalid mapping expression parameter specified: method.response.header.Content-Type] (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: f4b6ec17-f0ae-4e2a-aa18-b86ddcac807a; Proxy: null)
My Code:
const admin = api.root.addResource('admin');
admin.addMethod(
'GET',
new apigw.LambdaIntegration(hmtl_code, {
passthroughBehavior: apigw.PassthroughBehavior.WHEN_NO_MATCH,
requestTemplates: { 'application/json': '{"statusCode": 200}' },
integrationResponses: [
{
statusCode: "200",
responseParameters: {
'method.response.header.Content-Type': "'text/html'"
},
responseTemplates: { "text/html": "$input.path('$')" }
}
]
}),
{
methodResponses: [
{
statusCode: "200",
}
]
}
);
I tried it with a MockIntegration as well, but this Error message keeps popping up.
Help would be appreciated, thanks :)
Clearly a bit late here, but I just ran into the same issue and wish the cdk error was clearer.
The parameters in integrationResponses needs to be defined as part of methodResponses too.
From the docs for IntegrationResponse.responseParameters:
The destination must be an existing response parameter in the MethodResponse property.
So applying that to your code...
const admin = api.root.addResource('admin');
admin.addMethod(
'GET',
new apigw.LambdaIntegration(hmtl_code, {
passthroughBehavior: apigw.PassthroughBehavior.WHEN_NO_MATCH,
requestTemplates: { 'application/json': '{"statusCode": 200}' },
integrationResponses: [
{
statusCode: '200',
responseParameters: {
'method.response.header.Content-Type': "'text/html'",
},
responseTemplates: { 'text/html': "$input.path('$')" },
},
],
}),
{
methodResponses: [
{
statusCode: '200',
responseParameters: {
// a required response parameter
'method.response.header.Content-Type': true,
// an optional response parameter
'method.response.header.Content-Length': false,
},
},
],
}
);

Payment token not in response

==== SOLVED ====
Problem is solved. Adyen wants you to send the whole string as an object. JSON.parse(token). Make sure Google pay is enabled in the Adyen platform.
================
I'm working on transactions with Actions on Google and integration Google Pay. I followed all steps according to the documentation of Actions on Google.
To propose an order I send the following snippet seen below.
Notes:
gateway value is replaced for security reasons.
gatewayMerchantId value is replaced for security reasons.
I'm using a registered gateway.
I have not yet registered as Google partner though the business console so I have no access to the production API.
// Handle order with Google Pay.
conv.ask(new TransactionDecision({
orderOptions: {
requestDeliveryAddress: true,
userInfoOptions: {
userInfoProperties: [
'EMAIL',
],
},
},
paymentParameters: {
googlePaymentOption: {
facilitationSpec: JSON.stringify({
apiVersion: 2,
apiVersionMinor: 0,
environment: 'TEST',
merchantInfo: {
merchantName: 'Example Merchant',
merchantId: '12345678901234567890',
},
allowedPaymentMethods: [
{
type: 'CARD',
parameters: {
allowedAuthMethods: ['PAN_ONLY', 'CRYPTOGRAM_3DS'],
allowedCardNetworks: [
'AMEX', 'DISCOVER', 'JCB', 'MASTERCARD', 'VISA',
],
},
tokenizationSpecification: {
type: 'PAYMENT_GATEWAY',
parameters: {
'gateway': 'my_gateway',
'gatewayMerchantId': 'my_gateway_id',
},
},
},
],
transactionInfo: {
totalPriceStatus: 'FINAL',
totalPrice: prodPriceInclBtwInMicros.toString(),
currencyCode: 'EUR',
},
}),
},
},
presentationOptions: {
actionDisplayName: 'PLACE_ORDER',
},
order: order,
}));
The intent that handles the transaction decision value obtains the following arg value:
const arg = conv.arguments.get('TRANSACTION_DECISION_VALUE');
{
'#type': 'type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValue',
transactionDecision: 'ORDER_ACCEPTED',
order: {
googleOrderId: '02458320178127324049',
merchantOrderId: 'example',
userVisibleOrderId: 'example',
buyerInfo: {
email: 'example#example.com',
firstName: 'example',
lastName: 'example',
displayName: 'example example'
},
createTime: '2020-07-21T10:59:16.624Z',
lastUpdateTime: '2020-07-21T10:59:16.624Z',
transactionMerchant: { name: 'Example Merchant' },
contents: { lineItems: [Array] },
priceAttributes: [ [Object], [Object], [Object] ],
paymentData: { paymentResult: [Object], paymentInfo: [Object] },
purchase: {
status: 'CREATED',
type: 'RETAIL',
userVisibleStatusLabel: 'CREATED'
},
vertical: {
'#type': 'type.googleapis.com/google.actions.orders.v3.verticals.purchase.PurchaseOrderExtension',
status: 'CREATED',
type: 'RETAIL',
userVisibleStatusLabel: 'CREATED'
}
}
}
According to [Adyen][1] I should provide the payment token: 'Get the token from PaymentData response from the Google Pay API.' [Google][2] states that the token will be returned in a response object after the user approves the payment. This is certainly not the case as can be seen in the `arg` object.
By digging deeper into the paymentData, we get the following values:
{
paymentResult: {
googlePaymentData: '{"signature":"MEYCIQDS8Tiu9bprWqamQ24oNx+Wa43Wg6Vi3sP5PArDeOtOEAIhAOBqe4sQvN5tD390qWzDn9DIgwA8gjS8ajynrusOix6O","protocolVersion":"ECv1","signedMessage":"{\\"encryptedMessage\\":\\"Some_tokens_IUHASIDHUSAGFUAHS\\",\\"ephemeralPublicKey\\":\\"SOMEKEYSASD\\\\u003d\\",\\"tag\\":\\"SOMETAG_OIASJDJSOIJ\\\\u003d\\"}"}'
},
paymentInfo: {
paymentMethodDisplayInfo: {
paymentType: 'PAYMENT_CARD',
paymentMethodDisplayName: 'Visa •••• 1234'
},
paymentMethodProvenance: 'PAYMENT_METHOD_PROVENANCE_GOOGLE'
}
}
Still no token returned in the response... This will be necessary for the gateway.
Does anyone know how to resolve this? Or does this have to with the production Transaction API?
Any help is appreciated.
[1]: https://docs.adyen.com/payment-methods/google-pay/api-only
[2]: https://developers.google.com/pay/api/web/reference/response-objects#PaymentData

Error while setting up Extjs Rest Proxy Create function

I am using Rest proxy in Extjs Model as:
Ext.define('ThemeApp.model.peopleModel', {
extend: 'Ext.data.Model', fields: [
{ name: 'userId' },
{ name: 'title' },
{ name: 'body'}
],
proxy: {
type: 'rest',
format: 'json',
limitParam:"",
filterParam: "",
startParam:'',
pageParam:'',
url:'http://jsonplaceholder.typicode.com/posts/1',
api: {
read : 'http://jsonplaceholder.typicode.com/posts/1',
create: 'http://httpbin.org/post'},
headers: {'Content-Type': "application/json" },
reader: {
type: 'json',
//rootProperty:'issues'
},
writer: {
type: 'json'
}
In my view I am calling create function as:
var user = Ext.create('posts', {"userId": 124,"title": "sunt","body": "quia"});
user.save();
As I am testing everything on http://jsonplaceholder.typicode.com/ so I am expecting that code will work cause when I test GET and POST functionality via Postman utility everything works fine.
Can anyone point out my error?
I found my mistake.
In the following code I was not setting the correct name of my model, as it won't be "Posts"
var user = Ext.create('posts', {"userId": 124,"title": "sunt","body": "quia"});
user.save();
Also if you are trying with http://jsonplaceholder.typicode.com/ you are not supposed to send ID in the post request.

extjs4 proxy rest multiple request issue

Hi I am encountering a wierd behavior with my application:when I modify an item and then my proxy doas a put request, the first time is ok, the second time it sends two requests: the first with the data of the previous one, the second one with the actual data, the third time it sends three requests, onmy system it is not a big issue, because at end I get the right value on my database, but on my customer's system the result it is not always correct. Then I would like to remove this behavior.
this is my store:
Ext.create('Ext.data.Store',
{
storeId: 'bbCompaniesStore',
model:'Company',
pageSize: pageSize,
proxy:
{
idProperty : '_id',
type: 'rest',
url: 'data/companies/',
autoload: true,
noCache: true,
sortParam: undefined,
actionMethods:
{
create : 'PUT',
read : 'GET',
update : 'POST',
destroy: 'DELETE'
},
reader:
{
type: 'json',
root: 'data',
totalProperty: 'total'
},
},// proxy
listeners: {
exception: function(proxy, response, operation) {
Ext.gritter.add({
title: MongoVision.text['action.' + operation.action] || operation.action,
text: (operation.error ? operation.error.statusText : null) || MongoVision.text.exception
});
// Ext JS 4.0 does not handle this exception!
switch (operation.action) {
case 'create':
Ext.each(operation.records, function(record) {
record.store.remove(record);
});
break;
case 'destroy':
Ext.each(operation.records, function(record) {
if (record.removeStore) {
record.removeStore.insert(record.removeIndex, record);
}
});
break;
}
}
}
}
);
this is my model:
Ext.define('Company',
{
extend: 'Ext.data.Model',
fields: [
{
name : 'id',
type : 'string'
},
{
name :'firm',
type : 'string',
allowBlank: false
},{
name : 'p'
},
{
name: 'linee'
},
{
name : 'c'
},
{
name : 'data',
type: 'date'
},
{
name :'note'
},
{
name :'paese'
},
{
name : 'email'
},
{
name : 'telefono'
},
{
name : 'type'
},
{
name : 'website'
},
{
name : 'session_id'
},
{
name : 'group_id'
}
],
proxy : {
type : 'rest',
url : 'data/companies/'
}
}
);
after googling around I found a similar issue for extjs3, with no solution, I think it is strange that after so long time, there is no yet a solution; it should work now
I faced the same issue, resolved it by simply passing
batchActions: true when creating the Proxy. The default behavior for 'rest' proxies is to turn off batching.... (See extjs/src/data/proxy/Rest.js)